精华内容
下载资源
问答
  • 微信登录换取token的流程 如何将code变成openid和session_key 抛出错误异常和派发令牌 一:微信登录换取token的流程 多说无益,直接上图 小程序获取token.png 这里介绍的主要是后端开发的流程,前端的不是本文...
  • 在以后的网络请求时,客户端先查询本地的token,如果有则直接使用此令牌进行网络请求,没有则提示未登录,转到登陆注册界面。 此外,还可以在服务端或者客户端添加过期判别机制。 token的作用 token可以显著减少...
  • 一般的流程都是登录的时候返回一个代表此登录token,以后所有接口都带上此token,在所有接口调用之前拦截验证,一般都是通过AOP或者一个Filter、拦截器来实现。而退出的时候调用接口将此token删除即可。一般地,...

    详情参见: https://gitee.com/xxssyyyyssxx/token

    不管是客户端接口还是网页H5接口,一般我们都需要登录验证,即要求所有的接口访问都必须在登录之后,以确认身份,防止非法调用。一般的流程都是登录的时候返回一个代表此登录的token,以后所有接口都带上此token,在所有接口调用之前拦截验证,一般都是通过AOP或者一个Filter、拦截器来实现。而退出的时候调用接口将此token删除即可。一般地,为了对接口侵入最小,能做到统一处理,可以将此token放在header中。token一般都会设置一个有效期,过期了直接提示调用者需要登录以控制条转到登录页面引导登录。

    服务端设计:

    /**
     * token管理器
     * @author xiongshiyan
     */
    public interface TokenManager<M> {
        /**
         * 生成token
         * @param m 实体
         * @return token值
         */
        String createToken(M m);
    
        /**
         * 根据token获取
         * @param token token
         * @return 根据token获取的实体
         */
        M findByToken(String token);
    
        /**
         * 更新token的过期
         * @param token token
         */
        void updateExpires(String token);
    
        /**
         * 删除
         * @param token token
         * @return 删除是否成功
         */
        boolean deleteToken(String token);
    
        /**
         * 产生token
         * @param m 实体
         * @return token
         */
        String getToken(M m);
    
    
        /**
         * 踢人
         * @param m 实体
         * @param newToken 新token
         * @param doMore 还要做的事情
         */
        default void kickingOld(M m, String newToken, Runnable doMore){
            kickingOld(m , newToken);
    
            if(null != doMore){
                doMore.run();
            }
        }
    
        /**
         * 踢人
         * @param m 实体
         * @param newToken token
         */
        void kickingOld(M m, String newToken);
    }
    

    M代表登录实体,也可以是能代表登录人的唯一标识,使用泛型指定。createToken用于生成并保存token,findByToken用于通过token找到登录实体,updateExpires用于更新token的过期时间,deleteToken用于删除token(登录退出的时候),getToken生成token字符串。一般验证token是几乎每个接口都会用,所以必须保证速度,可以采用redis来保存。

    /**
     * 基于redis的token管理器基类
     * @author xiongshiyan at 2018/8/15 , contact me with email yanshixiong@126.com or phone 15208384257
     */
    public abstract class AbstractRedisTokenManager<M> implements TokenManager<M> {
        protected RedisUtil redisUtil;
    
        public AbstractRedisTokenManager(RedisUtil redisUtil){
            this.redisUtil = redisUtil;
        }
    
        @SuppressWarnings("unchecked")
        @Override
        public M findByToken(String token) {
            if(null == token){
                return null;
            }
            Object o = redisUtil.get(token);
            if(null == o){
                return null;
            }
            return (M) o;
        }
    
        @Override
        public boolean deleteToken(String token){
            Object o = redisUtil.get(token);
            if(null == o){
                return false;
            }
            redisUtil.del(token);
            return true;
        }
    }
    

    此基类实现了一些公共的方法,继承此类实现剩余的方法即可。

    1.允许多设备登录的实现。这种情形下,token可以随意生成,只要保证不重复即可。

    2.只允许单设备登录,即所谓的登录踢人,在登录的时候验证是够已经登录,如果已经登录就给出提示或者直接踢人登录。这种情形下,需要根据登录的标识确认是否已经登录,有两种解决方式,一种是在保存token的时候,既保存token》》实体的关系,还需要保存实体标识与token的关系;另外一种解决方式是token与实体标识强相关,根据实体标识即可算出token。

    以下的实现既支持多设备登录又支持单设备登录,设置multi即可。

    package cn.palmte.anfang.service.token.impl;
    
    import cn.palmte.anfang.redis.RedisUtil;
    import cn.palmte.anfang.service.token.AbstractRedisTokenManager;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    /**
     * API接口token管理器主要逻辑实现【支持多设备登录、踢人】
     * @author xiongshiyan at 2018/8/15 , contact me with email yanshixiong@126.com or phone 15208384257
     */
    @SuppressWarnings("unchecked")
    public abstract class BaseMultiTokenManager<M> extends AbstractRedisTokenManager<M> {
        private static final Logger logger = LoggerFactory.getLogger(BaseMultiTokenManager.class);
    
        private long apiExpires;
        /**
         * 多设备登录 ?
         */
        private boolean multi = false;
    
        public BaseMultiTokenManager(RedisUtil redisUtil, long apiExpires , boolean multi) {
            super(redisUtil);
            this.apiExpires = apiExpires;
            this.multi = multi;
        }
    
        @Override
        public String createToken(M m) {
            String token = getToken(m);
            redisUtil.set(token , m , apiExpires);
            logger.info("createToken token = {} , m={}" , token , m.toString());
            return token;
        }
    
        @Override
        public void updateExpires(String token){
            if(null == token){
                return;
            }
            redisUtil.expire(token , apiExpires);
            if(multi){
                return;
            }
    
            //单设备需要额外同步更新
            M m = (M) redisUtil.get(token);
            if(null != m){
                redisUtil.expire(key(m) , apiExpires);
            }
        }
    
        @Override
        public boolean deleteToken(String token) {
            //单设备需要额外删除
            M m = (M) redisUtil.get(token);
    
            boolean b = super.deleteToken(token);
            if(multi){
                return b;
            }
    
            String key = key(m);
            if(null != m){
                redisUtil.del(key);
            }
            logger.info("deleteToken token = {} , key={}" , token , key);
            return b;
        }
    
        @Override
        public void kickingOld(M m, String newToken) {
            if(multi){
                throw new IllegalStateException("多设备登录情况不允许踢人");
            }
            //1.删除以前登录人的token,以前的人就通不过校验
            String withPrefix = key(m);
            String oldToken = (String) redisUtil.get(withPrefix);
            if(null == oldToken){
                return;
            }
            deleteToken(oldToken);
    
            //2.重新建立实体和新token的联系
            //单设备需要额外保存标识和token的关系
            logger.info("kickingOld key={} , value={}" , withPrefix , newToken);
            redisUtil.set(withPrefix, newToken , apiExpires);
        }
    
        /**
         * 根据实体或者标识获取key
         * @param m 实体或者标识
         * @return 返回保存标识和token关系的key
         */
        abstract protected String key(M m);
    }
    

    直接使用实体比如手机号的

    /**
     * 客户端API接口token管理器【支持多设备登录】
     * @author xiongshiyan at 2018/8/15 , contact me with email yanshixiong@126.com or phone 15208384257
     */
    public class ApiTokenManager extends BaseMultiTokenManager<String> {
        private String apiTokenPrefix;
        public ApiTokenManager(RedisUtil redisUtil, String apiTokenPrefix, long apiExpires , boolean multi) {
            super(redisUtil, apiExpires, multi);
            this.apiTokenPrefix = apiTokenPrefix;
        }
        public ApiTokenManager(RedisUtil redisUtil, String apiTokenPrefix, long apiExpires) {
            super(redisUtil , apiExpires , false);
            this.apiTokenPrefix = apiTokenPrefix;
        }
    
        @Override
        public String getToken(String m){
            return apiTokenPrefix + "-" + nowStr() + CommonUtil.randomString(16);
        }
        private String nowStr(){
            return DatetimeUtils.toStr(new Date() , DatetimeUtils.SDF_DATETIME_SHORT);
        }
    
        @Override
        protected String key(String s) {
            return apiTokenPrefix + "-" + s;
        }
    }
    

    用实体的情况

    package cn.palmte.anfang.service.token.impl.model;
    
    import cn.palmte.anfang.model.Member;
    import cn.palmte.anfang.redis.RedisUtil;
    import cn.palmte.anfang.service.token.impl.BaseMultiTokenManager;
    import top.jfunc.common.datetime.DatetimeUtils;
    import top.jfunc.common.utils.CommonUtil;
    
    import java.util.Date;
    
    /**
     * 客户端API接口token管理器【支持多设备登录】
     * @author xiongshiyan at 2018/8/15 , contact me with email yanshixiong@126.com or phone 15208384257
     */
    public class ApiTokenManager extends BaseMultiTokenManager<Member> {
        private String apiTokenPrefix;
    
        public ApiTokenManager(RedisUtil redisUtil, String apiTokenPrefix, long apiExpires , boolean multi) {
            super(redisUtil, apiExpires, multi);
            this.apiTokenPrefix = apiTokenPrefix;
        }
        public ApiTokenManager(RedisUtil redisUtil, String apiTokenPrefix, long apiExpires) {
            super(redisUtil, apiExpires, false);
            this.apiTokenPrefix = apiTokenPrefix;
        }
    
        @Override
        public String getToken(Member m){
            return apiTokenPrefix + "-" + nowStr() + CommonUtil.randomString(16);
        }
        private String nowStr(){
            return DatetimeUtils.toStr(new Date() , DatetimeUtils.SDF_DATETIME_SHORT);
        }
    
        @Override
        protected String key(Member member){
            return apiTokenPrefix + "-" + member.getPhone();
        }
    }
    

     

    展开全文
  • Token

    千次阅读 2018-04-26 14:35:16
    验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端 客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里或者 Local Storage 里 客户端每次向服务端请求资源的时候需要带着服务端签发的 ...

     

    • 客户端使用用户名跟密码请求登录
    • 服务端收到请求,去验证用户名与密码
    • 验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端
    • 客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里或者 Local Storage 里
    • 客户端每次向服务端请求资源的时候需要带着服务端签发的 Token
    • 服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据

     

    1、Token的引入:Token是在客户端频繁向服务端请求数据,服务端频繁的去数据库查询用户名和密码并进行对比,判断用户名和密码正确与否,并作出相应提示,在这样的背景下,Token便应运而生。

     

    2、Token的定义:Token是服务端生成的一串字符串,以作客户端进行请求的一个令牌,当第一次登录后,服务器生成一个Token便将此Token返回给客户端,以后客户端只需带上这个Token前来请求数据即可,无需再次带上用户名和密码。

    3、使用Token的目的:Token的目的是为了减轻服务器的压力,减少频繁的查询数据库,使服务器更加健壮。

     

    二、如何使用Token?

    1、用设备号/设备mac地址作为Token(推荐)

    客户端:客户端在登录的时候获取设备的设备号/mac地址,并将其作为参数传递到服务端。

    服务端:服务端接收到该参数后,便用一个变量来接收同时将其作为Token保存在数据库,并将该Token设置到session中,客户端每次请求的时候都要统一拦截,并将客户端传递的token和服务器端session中的token进行对比,如果相同则放行,不同则拒绝。

    分析:此刻客户端和服务器端就统一了一个唯一的标识Token,而且保证了每一个设备拥有了一个唯一的会话。该方法的缺点是客户端需要带设备号/mac地址作为参数传递,而且服务器端还需要保存;优点是客户端不需重新登录,只要登录一次以后一直可以使用,至于超时的问题是有服务器这边来处理,如何处理?若服务器的Token超时后,服务器只需将客户端传递的Token向数据库中查询,同时并赋值给变量Token,如此,Token的超时又重新计时。

    2、用session值作为Token

    客户端:客户端只需携带用户名和密码登陆即可。

    客户端:客户端接收到用户名和密码后并判断,如果正确了就将本地获取sessionID作为Token返回给客户端,客户端以后只需带上请求数据即可。

    分析:这种方式使用的好处是方便,不用存储数据,但是缺点就是当session过期后,客户端必须重新登录才能进行访问数据。

    三、使用过程中出现的问题以及解决方案?

    刚才我们轻松介绍了Token的两种使用方式,但是在使用过程中我们还出现各种问题,Token第一种方法中我们隐藏了一个在网络不好或者并发请求时会导致多次重复提交数据的问题?
     

    >>>>>>>>>>>>>>

    setInterval(function(){ $(".login_Btn").click() }, 1000);

     

    微信:小程序

     

    appId(应用唯一标识,在微信开放平台提交应用审核通过后获得)
    secret(应用密钥AppSecret,在微信开放平台提交应用审核通过后获得)
    code
    grant_type(authorization_code)参数

    =================================================

    小程序登录登录凭证校验
    
    https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code
    openidstring用户唯一标识
    session_keystring会话密钥
    unionidstring用户在开放平台的唯一标识符,在满足 UnionID 下发条件的情况下会返回,详见 UnionID 机制说明
    errcodenumber错误码
    errmsgstring错误信息
    e:->jwt
    $wx=[
    'openid'=>'onbAZ4xqJjYPtPCz-O6DWmHN7EpA',
    'uniqid'=>'o9VTO0rrZOrGk6BTJOYicrJmIpIk',
    'session_key'=>'tiihtNczf5v6AKRyjwEUhQ=='
    ];
        $base_header=eyJhbGdvcml0aG0iOiJTSEEyNTYiLCJ0eXBlIjoiSldUIn0
        set    Array
            (
            [algorithm] => SHA256
            [type] => JWT
            )
    
        $payload:
            Array
            (
                [issuer] => StockSmallProcedure
                [issue_time] => 1556175091
                [expire_time] => 1558767091
                [uniqid] => a026700d9bb2d712d7bb98b406d6ec04 //md5(uniqid('JWT') . time()), //唯一标识
                [uid] => 6
                [session_key] => tiihtNczf5v6AKRyjwEUhQ==
            )
            =>base64Encode($payload)
        $base_payload=eyJpc3N1ZXIiOiJTdG9ja1NtYWxsUHJvY2VkdXJlIiwiaXNzdWVfdGltZSI6MTU1NjE3NTA5MSwiZXhwaXJlX3RpbWUiOjE1NTg3NjcwOTEsInVuaXFpZCI6ImEwMjY3MDBkOWJiMmQ3MTJkN2JiOThiNDA2ZDZlYzA0IiwidWlkIjoxNCwic2Vzc2lvbl9rZXkiOiJ0aWlodE5jemY1djZBS1J5andFVWhRPT0ifQ
            =>set_signature($payload):base64Encode(hash_hmac('sha256', json_encode($params), config('applet.app_secret')))
        $base_sign: IjdjNGQ0N2YzODhiNWYzY2RhZmU5ZjU5ODY3NjYyZjRmYWU4NzBhODVmNzM0YWZiODYyMzgzN2ZmZDNkOTg1Mzgi
    
        token=join('.', [$base_header, $base_payload, $base_sign])
        ='eyJhbGdvcml0aG0iOiJTSEEyNTYiLCJ0eXBlIjoiSldUIn0.eyJpc3N1ZXIiOiJTdG9ja1NtYWxsUHJvY2VkdXJlIiwiaXNzdWVfdGltZSI6MTU1NzM5MTAwNiwiZXhwaXJlX3RpbWUiOjE1NTk5ODMwMDYsInVuaXFpZCI6ImViYjBjNWM5MDVhZjFkNjY1MDhkZWM4ODU5ODQ2YWQ2IiwidWlkIjo2LCJzZXNzaW9uX2tleSI6InRpaWh0TmN6ZjV2NkFLUnlqd0VVaFE9PSJ9.Ijg1ODFkNzJmNzgzMGYyZGU1OTk4NjAyOWFhM2NhY2JmYzk0ZjJmMGIwYzYwZTZjZmQ4ZDg5YzU0NGYzYWM0Mjki'

    =================================================

    /**
     * 验证token
     */
    public function veriftJwt($data = '')
    {
        if (!$data) return false;
        if (substr_count($data, '.') < 2)
            return false;
        //拆分数据s
        list($header, $payload, $sign) = explode('.', $data);
        //验证三个参数
        if (!$header || !$payload || !$sign) return false;
        //验证头部信息
        $header = self::base64Decode($header);
        if (!$header['algorithm']) return false;
        $payload = self::base64Decode($payload);
        //验证签名
        $resultSign = self::set_signature($payload);
        if ($resultSign != $sign)
            return false;
        //验证签发时间大于服务器时间s
        if ($payload['issue_time'] && $payload['issue_time'] > time())
            return false;
        //验证过期时间
        if ($payload['expire_time'] && $payload['expire_time'] < time())
            return false;
        return $payload;
    }
    

    // db 验证

    =>

    Array
    (
        [id] => 6
        [applet_openid] => **************
        [public_openid] => **************
        [nickname] => 脚步
        [unionid] => ***************
        [avatarUrl] => img
        [session_key] => ************
    )

     

    ===================================================================

    微信小程序与微信公众号同一用户登录:
    微信小程序得到openid,然后通过openID得到用户的唯一标识,用户得以登录,
    然而,当我们调用微信公众号也同样的到openid,同一用户两个不同的openid,不能区分是否为同一用户,
    然后发现无论调用微信小程序还是微信公众号同一个用户的到unionid是相同的,所以我们就用unionid来区分是否为同一用户。

     

    全局Access Token


    https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
    {
        "access_token": "NU7Kr6v9L9TQaqm5NE3OTPctTZx797Wxw4Snd2WL2HHBqLCiXlDVOw2l-Se0I-WmOLLniAYLAwzhbYhXNjbLc_KAA092cxkmpj5FpuqNO0IL7bB0Exz5s5qC9Umypy-rz2y441W9qgfnmNtIZWSjSQ",
        "expires_in": 7200
    }

     

    网页授权access_token和普通access_token的区别

    1、微信网页授权是通过OAuth2.0机制实现的,在用户授权给公众号后,公众号可以获取到一个网页授权特有的接口调用凭证(网页授权access_token),通过网页授权access_token可以进行授权后接口调用,如获取用户基本信息;

    2、其他微信接口,需要通过基础支持中的“获取access_token”接口来获取到的普通access_token调用。

     

    用户管理-公众号获取用户基本信息(UnionID机制)


    https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID

    {
    "subscribe": 1,
    "openid": "o6_bmjrPTlm6_2sgVt7hMZOPfL2M",
    "nickname": "Band",
    "sex": 1,
    "language": "zh_CN",
    "city": "广州",
    "province": "广东",
    "country": "中国",
    "headimgurl":"http://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/0",
    "subscribe_time": 1382694957,
    "unionid": " o6_bmasdasdsad6_2sgVt7hMZOPfL"
    "remark": "",
    "groupid": 0,
    "tagid_list":[128,2],
    "subscribe_scene": "ADD_SCENE_QR_CODE",
    "qr_scene": 98765,
    "qr_scene_str": ""
    }

     

    网页授权

    1 第一步:用户同意授权,获取code

    https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect

    如果用户同意授权,页面将跳转至 redirect_uri/?code=CODE&state=STATE

     

    2 第二步:通过code换取网页授权access_token

    https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
    {
    "access_token":"ACCESS_TOKEN",
    "expires_in":7200,
    "refresh_token":"REFRESH_TOKEN", // 参数code是一次性的参数,需要重新获取,而重新获取就需要用户再一次登录才能获取code
    "openid":"OPENID",
    "scope":"SCOPE"
    }
    

    3 第三步:刷新access_token(如果需要)

    https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN
    {
    "access_token":"ACCESS_TOKEN",
    "expires_in":7200,
    "refresh_token":"REFRESH_TOKEN",
    "openid":"OPENID",
    "scope":"SCOPE"
    }

    4 第四步:拉取用户信息(需scope为 snsapi_userinfo)

    https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
    {
        "openid":" OPENID",
        " nickname": NICKNAME,
        "sex":"1",
        "province":"PROVINCE"
        "city":"CITY",
        "country":"COUNTRY",
        "headimgurl":                  "http://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46",
        "privilege":[ "PRIVILEGE1" "PRIVILEGE2"     ],
        "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
    }

    5 附:检验授权凭证(access_token)是否有效

    https://api.weixin.qq.com/sns/auth?access_token=ACCESS_TOKEN&openid=OPENID
    { "errcode":0,"errmsg":"ok"}
    

    ==================================================================

    网页开发:微信JS-SDK说明文档

    微信JS-SDK是微信公众平台 面向网页开发者提供的基于微信内的网页开发工具包。

    通过使用微信JS-SDK,网页开发者可借助微信高效地使用拍照、选图、语音、位置等手机系统的能力,同时可以直接使用微信分享、扫一扫、卡券、支付等微信特有的能力,为微信用户提供更优质的网页体验。

    GET:https://api.weixin.qq.com/cgi-bin/ticket/getticket

    jsapi_ticket是公众号用于调用微信JS接口的临时票据

    展开全文
  • token做自动登录

    千次阅读 2019-08-19 22:17:46
    前端自动登录 OpenSSL + perl软件安装: https://blog.csdn.net/sunhuansheng/article/details/82218678 OpenSSl 、 Perl这个软件安装无要求,一路next 先装Perl,在装OpenSSl 检查你的环境变量中的系统变量是否有这...

    token

    身份验证 token

    • 前端自动登录
    • OpenSSL + perl软件安装: https://blog.csdn.net/sunhuansheng/article/details/82218678
      • OpenSSl 、 Perl这个软件安装无要求,一路next
      • 先装Perl,在装OpenSSl
      • 检查你的环境变量中的系统变量是否有这两个软件的启动路径
    1. 先构建前端页面,发送请求
      $('button').on('click',function () {
      $.ajax({
        url: 'http://localhost:3000/login',
        method: 'POST',
        data: {
          username: $('#username').val(),
          password: $('#password').val(),
          token: localStorage.getItem('token')        // 当第一次发送登录请求式,我们携带一个token参数,就是要告诉后端,我是第一次登录,我需要token字符做后期自动登录
        },
        success: function ( res ) {
         if ( res ) {
          const result = JSON.parse( res )
          localStorage.setItem('token',result.token )
          location.href = "./index.html"
         }
        }
      })
      

    })

    2. 使用express搭建路由写接口,以模块化形式导出,创建路由中间件
    3. 解决跨域问题 res.setHeader('A-C-A-O','*'),req.body得到前端发送的数据
    4. 新建rsa文件夹创建两个文件,一个私钥一个公钥。通过私钥产生token,通过公钥解密token。
    ```js
    // 1.产生公钥和私钥
    // 产生私钥  openssl genrsa -out ./private_key.pem 1024    1024 代表私钥长度
    // 产生公钥  openssl rsa -in ./private_key.pem -pubout -out ./public_key.pem
    
    
    1. 通过文件系统把私钥和公钥里面的内容读出来
     const privateKey = fs.readFileSync( path.join( __dirname,'../rsa/private_key.pem') )
    
      const publicKey = fs.readFileSync( path.join( __dirname, '../rsa/public_key.pem' ))
    
    1. 通过引入jwt这个工具,将用户信息和私钥结合进行加密:
      • $ npm install jaonwebtoken -s
           // 通过jwt将用户名和私钥结合 ,然后在通过RS256加密算法,输出最终的token
      
        const token = jwt.sign( username, privateKey, { algorithm: 'RS256' })
        
        
        /*   
        通过public进行解密
        const newToken = 'eyJhbGciOiJSUzI1NiJ9.MTE.SrtxG9-mwK2MGWL4vrJjq9FAghlL3-daZUV9hUA3yOrnMGXFLVKE8Zwj90f0eB02D7nfclYd1PN8DGcQS62u8Qc8CGSbtERoSJuDG_D1fXR-my3HmzXAVPkxde5e7764_bYaZ85atn15B3LLUZiQMYfryGS2z4DJ58-J3RylhgY'
      
        const decode = jwt.verify( newToken,publicKey ) 
        
        console.log( decode )
      */
      
    2. 把token发给前端,前端存到cookie里
    3. 取token,如果有直接跳转到首页
    function load () {
        const token = localStorage.getItem('token')
        if ( token ) {
          //条件成立,证明token存在
          setTimeout(function () {
            location.href = './index.html'
          },1000)
        } else {
          alert( '用户民或是密码过期了,请重新登录' )
        }
      }
    
      $('button').on('click',function () {
        $.ajax({
          url: 'http://localhost:3000/login',
          method: 'POST',
          data: {
            username: $('#username').val(),
            password: $('#password').val(),
            token: localStorage.getItem('token')        // 当第一次发送登录请求式,我们携带一个token参数,就是要告诉后端,我是第一次登录,我需要token字符做后期自动登录
          },
          success: function ( res ) {
           if ( res ) {
            const result = JSON.parse( res )
            localStorage.setItem('token',result.token )
            location.href = "./index.html"
           }
          }
        })
      })
    
    展开全文
  • SpringBoot整合token实现登录认证

    万次阅读 多人点赞 2019-06-14 17:43:32
    最近在做登录认证的时候,遇到了验证的问题,如何用token验证困扰了许久,所有在网上查询了许多博客,总结了一下,希望能帮助到大家,好了,废话不多说,直接上代码

    标题SpringBoot整合JWT实现登录认证

    1.pom.xml

    <dependencies>
    		<dependency>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter-web</artifactId>
    		</dependency>
    
    		<dependency>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter-test</artifactId>
    			<scope>test</scope>
    		</dependency>
    		
    		<dependency>
    		      <groupId>com.auth0</groupId>
    		      <artifactId>java-jwt</artifactId>
    		      <version>3.4.0</version>
    		</dependency>
    		
    		 <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <scope>runtime</scope>
            </dependency>
            
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>1.3.2</version>
            </dependency>
            
    		 <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>1.2.47</version>
            </dependency>
    
    		<dependency>
    			<groupId>io.springfox</groupId>
    			<artifactId>springfox-swagger2</artifactId>
    			<version>2.8.0</version>
    		</dependency>
    		<dependency>
    			<groupId>io.springfox</groupId>
    			<artifactId>springfox-swagger-ui</artifactId>
    			<version>2.8.0</version>
    		</dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.0</version>
            </dependency>
    
        </dependencies>
    
    

    2.实体类

    @Data
    public class User {
    	private String id;
        private String username;
        private String password;
    }
    

    3.Mapper接口

    /**
     * @author qiaoyn
     * @date 2019/06/14
     */
    @Mapper
    public interface UserMapper {
    	
        User findByUsername(String username);
        
        User findUserById(String id);
    
    }
    

    4.service层

    @Service
    public class UserService {
        @Autowired
        private UserMapper userMapper;
        public User findByUsername(User user){
            return userMapper.findByUsername(user.getUsername());
        }
        public User findUserById(String userId) {
            return userMapper.findUserById(userId);
        }
    }
    
    /***
     * token 下发
    * @Title: TokenService.java 
    * @author qiaoyn
    * @date 2019/06/14
    * @version V1.0
     */
    @Service
    public class TokenService {
    
    	public String getToken(User user) {
    		Date start = new Date();
    		long currentTime = System.currentTimeMillis() + 60* 60 * 1000;//一小时有效时间
    		Date end = new Date(currentTime);
    		String token = "";
    		
    		token = JWT.create().withAudience(user.getId()).withIssuedAt(start).withExpiresAt(end)
    				.sign(Algorithm.HMAC256(user.getPassword()));
    		return token;
    	}
    }
    
    

    5.Api层

    @RestController
    public class UserApi {
    	@Autowired
    	UserService userService;
    	@Autowired
    	TokenService tokenService;
    
    	// 登录
    	@ApiOperation(value = "登陆", notes = "登陆")
    	@RequestMapping(value = "/login" ,method = RequestMethod.GET)
    	public Object login(User user, HttpServletResponse response) {
    		JSONObject jsonObject = new JSONObject();
    		User userForBase = new User();
    		userForBase.setId(userService.findByUsername(user).getId());
    		userForBase.setUsername(userService.findByUsername(user).getUsername());
    		userForBase.setPassword(userService.findByUsername(user).getPassword());
    		if (!userForBase.getPassword().equals(user.getPassword())) {
    			jsonObject.put("message", "登录失败,密码错误");
    			return jsonObject;
    		} else {
    			String token = tokenService.getToken(userForBase);
    			jsonObject.put("token", token);
    
    			Cookie cookie = new Cookie("token", token);
    			cookie.setPath("/");
    			response.addCookie(cookie);
    
    			return jsonObject;
    
    		}
    	}
    	/***
    	 * 这个请求需要验证token才能访问
    	 * 
    	 * @author: qiaoyn
    	 * @date 2019/06/14
    	 * @return String 返回类型
    	 */
    	@UserLoginToken
    	@ApiOperation(value = "获取信息", notes = "获取信息")
    	@RequestMapping(value = "/getMessage" ,method = RequestMethod.GET)
    	public String getMessage() {
    
    		// 取出token中带的用户id 进行操作
    		System.out.println(TokenUtil.getTokenUserId());
    
    		return "您已通过验证";
    	}
    }
    
    

    6.util

    /* 
    * @author qiaoyn
    * @date 2019/06/14
    * @version 1.0 
    */
    public class TokenUtil {
    
    	public static String getTokenUserId() {
    		String token = getRequest().getHeader("token");// 从 http 请求头中取出 token
    		String userId = JWT.decode(token).getAudience().get(0);
    		return userId;
    	}
    
    	/**
    	 * 获取request
    	 * 
    	 * @return
    	 */
    	public static HttpServletRequest getRequest() {
    		ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
    				.getRequestAttributes();
    		return requestAttributes == null ? null : requestAttributes.getRequest();
    	}
    }
    
    

    7.Interceptor

    /**
     * 拦截器
     * @author qiaoyn
     * @date 2019/06/14
     */
    public class AuthenticationInterceptor implements HandlerInterceptor {
        @Autowired
        UserService userService;
        @Override
        public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {
            String token = httpServletRequest.getHeader("token");// 从 http 请求头中取出 token
            // 如果不是映射到方法直接通过
            if(!(object instanceof HandlerMethod)){
                return true;
            }
            HandlerMethod handlerMethod=(HandlerMethod)object;
            Method method=handlerMethod.getMethod();
            //检查是否有passtoken注释,有则跳过认证
            if (method.isAnnotationPresent(PassToken.class)) {
                PassToken passToken = method.getAnnotation(PassToken.class);
                if (passToken.required()) {
                    return true;
                }
            }
            //检查有没有需要用户权限的注解
            if (method.isAnnotationPresent(UserLoginToken.class)) {
                UserLoginToken userLoginToken = method.getAnnotation(UserLoginToken.class);
                if (userLoginToken.required()) {
                    // 执行认证
                    if (token == null) {
                        throw new RuntimeException("无token,请重新登录");
                    }
                    // 获取 token 中的 user id
                    String userId;
                    try {
                        userId = JWT.decode(token).getAudience().get(0);
                    } catch (JWTDecodeException j) {
                        throw new RuntimeException("401");
                    }
                    User user = userService.findUserById(userId);
                    if (user == null) {
                        throw new RuntimeException("用户不存在,请重新登录");
                    }
                    // 验证 token
                    JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build();
                    try {
                        jwtVerifier.verify(token);
                    } catch (JWTVerificationException e) {
                        throw new RuntimeException("401");
                    }
                    return true;
                }
            }
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
    
        }
        @Override
        public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
    
        }
    }
    
    

    8.cofig

    /***
     * 新建Token拦截器
    * @Title: InterceptorConfig.java 
    * @author qiaoyn
    * @date 2019/06/14
    * @version V1.0
     */
    @Configuration
    public class InterceptorConfig implements WebMvcConfigurer {
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(authenticationInterceptor())
                    .addPathPatterns("/**");    // 拦截所有请求,通过判断是否有 @LoginRequired 注解 决定是否需要登录
        }
        @Bean
        public AuthenticationInterceptor authenticationInterceptor() {
            return new AuthenticationInterceptor();
        }
    	@Override
    	public void addArgumentResolvers(List<HandlerMethodArgumentResolver> arg0) {
    		// TODO Auto-generated method stub
    		
    	}
    	@Override
    	public void addCorsMappings(CorsRegistry arg0) {
    		// TODO Auto-generated method stub
    		
    	}
    	@Override
    	public void addFormatters(FormatterRegistry arg0) {
    		// TODO Auto-generated method stub
    		
    	}
    	@Override
    	public void addResourceHandlers(ResourceHandlerRegistry arg0) {
    		// TODO Auto-generated method stub
    		
    	}
    	@Override
    	public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> arg0) {
    		// TODO Auto-generated method stub
    		
    	}
    	@Override
    	public void addViewControllers(ViewControllerRegistry arg0) {
    		// TODO Auto-generated method stub
    		
    	}
    	@Override
    	public void configureAsyncSupport(AsyncSupportConfigurer arg0) {
    		// TODO Auto-generated method stub
    		
    	}
    	@Override
    	public void configureContentNegotiation(ContentNegotiationConfigurer arg0) {
    		// TODO Auto-generated method stub
    		
    	}
    	@Override
    	public void configureDefaultServletHandling(DefaultServletHandlerConfigurer arg0) {
    		// TODO Auto-generated method stub
    		
    	}
    	@Override
    	public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> arg0) {
    		// TODO Auto-generated method stub
    		
    	}
    	@Override
    	public void configureMessageConverters(List<HttpMessageConverter<?>> arg0) {
    		// TODO Auto-generated method stub
    		
    	}
    	@Override
    	public void configurePathMatch(PathMatchConfigurer arg0) {
    		// TODO Auto-generated method stub
    		
    	}
    	@Override
    	public void configureViewResolvers(ViewResolverRegistry arg0) {
    		// TODO Auto-generated method stub
    		
    	}
    	@Override
    	public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> arg0) {
    		// TODO Auto-generated method stub
    		
    	}
    	@Override
    	public void extendMessageConverters(List<HttpMessageConverter<?>> arg0) {
    		// TODO Auto-generated method stub
    		
    	}
    	@Override
    	public MessageCodesResolver getMessageCodesResolver() {
    		// TODO Auto-generated method stub
    		return null;
    	}
    	@Override
    	public Validator getValidator() {
    		// TODO Auto-generated method stub
    		return null;
    	}
    	
    }
    
    

    9.annotation

    /***
     * 用来跳过验证的 PassToken
     * @author qiaoyn
     * @date 2019/06/14
     */
    @Target({ElementType.METHOD, ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface PassToken {
        boolean required() default true;
    }
    
    /**
     * 用于登录后才能操作的token
     * @author qiaoyn
     * @date 2019/06/14
     */
    @Target({ElementType.METHOD, ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface UserLoginToken {
        boolean required() default true;
    }
    
    /*RetentionPolicy.RUNTIME:这种类型的Annotations将被JVM保留,
    所以他们能在运行时被JVM或其他使用反射机制的代码所读取和使用。*/
    

    10.mapper.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
    <mapper namespace="com.example.demo.mapper.UserMapper">
        <select id="findByUsername" resultType="com.example.demo.entity.User">
          SELECT id,password
          FROM user
          WHERE
          username=#{username}
        </select>
        <select id="findUserById" resultType="com.example.demo.entity.User">
            SELECT username,password
            FROM user
            WHERE
            id=#{id}
        </select>
    
    </mapper>
    

    11.测试
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    数据库文件如下所示
    在这里插入图片描述
    好了,今天分享就到此了。

    展开全文
  • springboot基于token实现登录认证

    千次阅读 2020-08-12 15:20:03
    最近因为项目需求,需采用token的方式实现登录认证,而不再使用session的方式登录,因而采用springboot集成JWT生成token实现登录认证。 1.首先添加jwt所需jar包 <dependency> <groupId>io.jsonwebtoken...
  • shiro框架中如何通过用户名密码在代码中直接登录? 首先在网上找了下,找到了这种方式:     Subject currentUser = SecurityUtils.getSubject(); UsernamePasswordToken toke...
  • Java令牌Token登录与退出

    千次阅读 2020-05-25 20:34:15
    Java令牌Token登录与退出 Token 之前的博客已经介绍了各种登录的方式,现在直接介绍一种现在比较流行的登录方式,无状态登录,只需要客户端携带令牌就能登陆,服务器不再存储登录状态。突然粉丝量爆棚,开心死了,...
  • Java Token登录验证 生成解析Token

    千次阅读 2020-06-05 22:32:59
    Java Token登录验证 使用jjwt生成和解析JWT java基于token验证之登陆验证 等 什么是Token? 我的理解来说 token就是你访问服务器的口令,只要token合法,正确,你就能获取到后端数据 当用户第一次登陆后,用户名密码...
  • Jmeter获取登录token

    千次阅读 2019-05-09 11:29:42
    入门级Jmeter获取token,乱码处理
  • nodejs实现jwt token认证登录

    千次阅读 2020-08-28 18:03:26
    在本文中采用koa2框架编写接口的方式实现一遍jwt token登录认证的流程,主要涉及的知识点有如何生成登录校验码,koa2如何配置session以及前后端对token的处理. githup项目地址 session配置 在koa2项目中安装一个...
  • 微信token登录

    千次阅读 2018-08-07 19:58:01
    使用snsapi_base可以让移动端网页授权绕过跳转授权登录页请求用户授权的动作,直接跳转第三方网页带上授权临时票据(code),但会使得用户已授权作用域(scope)仅为snsapi_base,从而导致无法获取到需要用户授权才...
  • SpringBoot实现基于token登录验证

    千次阅读 2020-09-17 16:10:07
    SpringBoot实现基于token登录验证        基于token登录验证实现原理:客户端通过用户名和密码调用登录接口,当验证数据库中存在该用户后,将用户的信息按照token的生成规则...
  • Token验证登录状态的简单实现(转)

    千次阅读 2019-05-27 10:21:49
    用户发出登录请求,带着用户名和密码到服务器经行验证,服务器验证成功就在后台生成一个token返回给客户端 客户端将token存储到cookie中,服务端将token存储到redis中,可以设置存储token的有效期。 后续客户端的...
  • VUE实现token登录验证

    千次阅读 多人点赞 2019-04-01 17:47:14
    实现这个登录功能的过程真是一波三折,中途出现了bug,整了两三天才解决了问题,心力交瘁,简直一个...现在详细地记录一下实现token登录验证的步骤,以防以后再犯错 1.封装store对token的操作方法 首先在src目录下...
  • Spring Boot 2.X 实战--Shiro (Token)登录和验证 主要介绍了 Spring Boot 整合 Spring Security 实现 Token登录和认证,这一小节中,我们将实现 Spring Boot 整合 Shiro 实现 Token登录和认证。 目录结构 ...
  • 用户登录token验证

    万次阅读 多人点赞 2017-06-13 22:10:01
    可能还有很多小伙伴对token概念朦朦胧胧,今天笔者以项目中的用户登录token验证需求跟大家讲讲其中的来龙去脉,希望能够理清大伙的思路。 2.需求分析 这个需求可能早已是老生常谈,但我觉得它永远也不会过时 ①...
  • idea使用token登录github

    千次阅读 2021-02-28 00:34:42
    一、问题描述 ...之前也试过其他方法,但是当使用token后,发现token真的很方便,所以总结记录 1.github中获取token Settings->Developer settings->Personal access tokens->Generate new token N
  • token实现单点登录原理

    千次阅读 2019-08-28 16:03:10
    在日常的业务中,登录功能是非常常见的,除了最简单的cookie校验登录与session会话实现登录之外,针对较复杂的场景还可以使用更高安全的自定义加密令牌token来实现登录功能,此文将会详细介绍这种登录系统的实现方式...
  • 通过ajax分配相应的clientID和Secret及用户名和...测试页面click_me_please_iframe.html包含相应的刷新和认证,同时refresh_token以文件的形式进行存储,方便下次程序直接使用,不必要在产生新的token;开发工具是vs2017
  • 基于token登录验证基于token登录验证实现1. Redis数据库 存储token2. `JWT` 产生token3. 实现登录验证基于Session的登录验证 基于token登录验证 token(令牌) ...登录的信息仅需一个key-value,如果直接
  • token的使用基于Python的登录注册功能

    千次阅读 2018-10-13 09:55:43
    使用基于 Token 的身份验证方法,在服务端不需要存储用户的登录记录。大概的流程是这样的: 客户端使用用户名跟密码请求登录 服务端收到请求,去验证用户名与密码 验证成功后,服务端会签发一个 Token,再把这个 ...
  • springmvc-权限拦截及登录token

    千次阅读 2018-05-23 16:20:40
    //如果不是映射到方法直接通过 if (!(handler instanceof HandlerMethod)) { return true; } HandlerMethod handlerMethod = (HandlerMethod) handler; Method method = handlerMethod.getMethod(); //从...
  • JwtToken登录授权方案

    千次阅读 2020-06-15 11:27:54
    使用举例三、jwt的续签方案过期之后刷新token的方案设计四、jwt实现单一登录功能五、token的注销方案六、jwt的优缺点优点跨域问题的解决无状态缺点token的续签问题七、jwt的适用场景一次性验证restful api的无状态...
  • app登录token设计

    万次阅读 2017-12-06 19:25:28
    1.登录的时候,登录成功之后,我们需要给他分配一个token。(1)token可以是文件的形式存着;(2)也可以存在数据库,但是存放在数据库,我个人不推荐,因为每次调用api接口都会对比,这样做法会加重服务器压力;(3...
  • Flask定义token以及利用token验证登录

    千次阅读 2018-12-25 15:17:49
    导入的包 from flask import Flask , jsonify , current_app ...token的生成函数 ...generate_token ... token ...这样你第二步可以直接输入token,不需要输入用户名密码也可以得到 相应的值了!
  • (2)服务器进行效验, 通过后生成token, 包含信息有密钥, uid, 过期时间, 一些随机算法等 ,然后返回给前端 (3)前端将token保存在本地中, 建议使用localstorage进行保存. 下次对服务器发送请求时, 带上本地存储的...
  • 微信小程序Token登录验证

    千次阅读 2021-02-24 23:28:48
    上图是微信开发文档提供的图。 最近开发一款小程序,看了许久的微信文档,这里来记录一下其中的...前端以后每次请求都会携带该自定义登录状态,后端进行登录状态的判断,正常就返回业务数据,否则重新登陆,获取新的.

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 85,388
精华内容 34,155
关键字:

token直接登录