• flask刷新token


    我们在做前后端分离的项目中,最常用的都是使用token认证。

    登录后将用户信息,过期时间以及私钥一起加密生成token,但是比较头疼的就是token过期刷新的问题,因为用户在登录后,如果在使用过程中,突然提示token过期了,需要重新登录,会觉得很奇怪。

    我使用的方式,是在解析token的时候,如果token过期了,但是还在可刷新的时间范围内,我们应该自动刷新token,并将新的token返回给用户。

    但是如果前端采用异步请求,同时发来了多个接口的话,我们不可能对每个请求的token都进行刷新。

    我的解决方案是,将过期但还在刷新范围的token存入redis,同时设置token的过期时间为可刷新时间,过了可刷新时间,token就会被自动删除

    当前端多个请求过来时,会对请求带来的token进行验证,分三种情况:

      1)如果token已经过了刷新时间,则抛出异常。

      2)如果token不在redis中,表示刚刚过期,还没有进行刷新token操作,需要刷新token。

      3)如果token在redis中,则权限默认通过。

    下面上代码:

      1)为了给token加上可刷新时间,需要重写TimedJSONWebSignatureSerializer 的make_header和loads方法

    from itsdangerous import TimedJSONWebSignatureSerializer as Serializer_
    import redis
    r = redis.Redis(host="127.0.0.1", port=6379,db=0)
    class Serializer(Serializer_):
        def __init__(self, secret_key, expires_in=None, **kwargs):
            self.expires_in = expires_in
            super(Serializer, self).__init__(secret_key, expires_in, **kwargs)
    
        def make_header(self, header_fields):
            header = JSONWebSignatureSerializer.make_header(self, header_fields)
            iat = self.now()
            exp = iat + self.expires_in
            refresh_exp = iat+current_app.config["REFRESH_TIME"]
            header["iat"] = iat
            header["exp"] = exp
            header["refresh_exp"] = refresh_exp
            return header
    
        def loads(self, s, salt=None, return_header=False):
            payload, header = JSONWebSignatureSerializer.loads(
                self, s, salt, return_header=True
            )
    
            if "exp" not in header:
                raise BadSignature("Missing expiry date", payload=payload)
    
            int_date_error = BadHeader("Expiry date is not an IntDate", payload=payload)
            try:
                header["exp"] = int(header["exp"])
            except ValueError:
                raise int_date_error
            if header["exp"] < 0:
                raise int_date_error
            now = self.now()
            if header["exp"] < now:
                if header["refresh_exp"]<now:
                    # 已经过了可刷新时间,直接抛出异常
                    raise SignatureExpired(
                        "Signature expired",
                        payload=payload,
                        date_signed=self.get_issue_date(header),
                    )
                else:
                    # TODO 增加判断,看是否有存储在redis中,如果有存储过,表示token已经被刷新过了,直接放行即可。
                    if r.get(s):
                        return payload
                    pxt = header["refresh_exp"] - now
                    if pxt>0:
                        r.set(s, header["exp"], px = pxt)
                    # 还在可刷新时间内
                    # 生成新的token返回给前端
                    serializer = Serializer(current_app.config["SECRET_KEY"], expires_in=self.expires_in)
                    # 调用serializer的dumps方法将uid和type写入生成token
                    token = serializer.dumps(payload)
                    res = make_response()
                    res.headers["Authorization"] = token
                    res.set_cookie("authorization",token.decode("ascii"))
                    return payload, token
            if return_header:
                return payload, header
            return payload 

      2)认证权限

    auth = HTTPBasicAuth()
    user = namedtuple("User",["uid","type","scope"])
    
    @auth.verify_password
    def check_authorization(token, pwd):
        user_info = check_auth_token(token)
        if not user_info:
            return False
        else:
            if isinstance(user_info, tuple):
                user_info_ = user_info[0]
                token = user_info[1]
            else:
                user_info_ = user_info
            g.user = user_info_
            return True if not token else token
    
    
    def check_auth_token(token):
        serialzer = Serializer(current_app.config["SECRET_KEY"])
        try:
            s = serialzer.loads(token)
        except BadSignature:
            raise AuthFailed(msg="token is invalid", error_code=1004)
        except SignatureExpired:
            raise AuthFailed(msg="token is expired", error_code=1004)
        token = ""
        if isinstance(s, tuple):
            u_info = s[0]
            token = s[1]
        else:
            u_info = s
        uid = u_info["uid"]
        type = u_info["type"]
        scope = u_info["scope"]
        return user(uid, type, scope), token
    

      3)生成新的token后,将新的token放入response的header中,前端人员从response header中去取authorization

    @api.router("/get/<int:uid>")
    @auth.login_required
    def get_user(uid, token=None):
        user = User.query.get_or_404(uid)
        res_json = jsonify(user)
        res = make_response(res_json)
        res.headers["Authorization"] = token
        return res
    

      

      

  • 相关阅读:
    js总结 (1)数据类型以及转换的知识整理
    伪元素 hover 的几种用法总结
    一套网页 同时适配pc端和移动端的布局思路(不要怕固定定位 和百分比)
    移动端 高亮小知识 -webkit-tap-highlight-color:transparent; tap-highlight-color:transparent;
    移动端布局 viewport 用法 简单总结
    Linux系统登陆成功和登陆失败日志的查看
    Windows系统ntlm哈希与解密、本地RDP连接密码获取
    office小技巧和一些奇怪问题的汇总解决
    阿里云镜像导出至本地操作
    sqlite数据库文件的打开与读取
  • 原文地址:https://www.cnblogs.com/fiona-zhong/p/10315499.html
Copyright © 2020-2023  润新知