我们在做前后端分离的项目中,最常用的都是使用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

  

  

最新文章

  1. SharePoint 2103 Check user permission on list
  2. python爬虫—爬取百度百科数据
  3. UISlider相关
  4. Mysql数据库操作系统及配置参数优化
  5. Redis持久化-数据丢失及解决(转载)
  6. Array和ArrayList互相转换
  7. Mongoose中关联查询populate的使用
  8. JS函数式编程【译】2.2 与函数共舞
  9. DBCP,C3P0,Tomcat_JDBC 性能及稳定性测试
  10. 自定义filter包
  11. java小型科学计算器
  12. HTML5分析实战WebSockets基本介绍
  13. 老李推荐:第8章3节《MonkeyRunner源码剖析》MonkeyRunner启动运行过程-启动AndroidDebugBridge 3
  14. mongodb监控工具mongostat
  15. jQuery的ajax使用
  16. Iconfont 在HTML中的使用
  17. Intellij Idea 2016创建web项目
  18. 使用 Spring 2.5 注释驱动的 IoC 功能
  19. beego快速入门
  20. Beta 冲刺 五

热门文章

  1. SpringCloud系列——Eureka 服务注册与发现
  2. 浅谈CLR CTS CLS。。。
  3. Java学习笔记之——LinkedList
  4. MySQL优化COUNT()查询
  5. web前端图片上传
  6. vue遍历数组和对象的方法以及他们之间的区别
  7. 后端开发者的Vue学习之路(四)
  8. 使用Semaphore控制对资源的多个副本的并发访问
  9. SAP MM 事务代码MI31之思考
  10. 跨进程SharedPreferences异常。