JWT refreshtoken 实践

Json web token (JWT), 根据官网的定义,是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登陆(SSO)场景。JWT的声明通常被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也能够增长一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。
详细介绍能够查看这篇文章 理解JWT(JSON Web Token)认证及实践

JWT 特色

优势

  • 体积小,于是传输速度快
  • 传输方式多样,能够经过URL/POST参数/HTTP头部等方式传输
  • 严格的结构化。它自身(在 payload 中)就包含了全部与用户相关的验证消息,如用户可访问路由、访问有效期等信息,服务器无需再去链接数据库验证信息的有效性,而且 payload 支持为你的应用而定制化。
  • 支持跨域验证,能够应用于单点登陆。

存在的问题

JWT 自身(在 payload 中)就包含了全部与用户相关的验证消息,因此一般状况下不须要保存。这种设计存在几个问题:html

  1. Token不能撤销--客户端重置密码后以前的JWT依然可使用(JWT 并无过时或者失效
  2. 不支持refresh token,JWT过时后须要执行登陆受权的完整流程
  3. 没法知道用户签发了几个JWT

针对第一个问题,可能的解决方法有:python

  1. 保存JWT到数据库(或Redis),这样能够针对每一个JWT单独校验
  2. 在重置密码等须要做废以前所有JWT时,把操做时间点记录到数据库(或Redis),校验JWT时同时判断此JWT建立以后有没有太重置密码等相似操做,若是有校验不经过

固然,这种解决方法都会多一次数据库请求,JWT自身可校验的优点会有所减小,同时也会影响认证效率。web

这篇文章主要介绍解决第二个问题(不支持refresh token)的思路。redis

refresh token

refresh token是OAuth2 认证中的一个概念,和OAuth2 的access token 一块儿生成,表示更新令牌,过时所需时间比access toen 要长,能够用来获取下一次的access token。数据库

若是JWT 须要添加 refresh token支持,refresh token须要知足的条件有一下几项:小程序

  1. 和JWT一块儿生成返回给客户端
  2. 有实效时间,有效时间比JWT要长
  3. 只能用来换取下一次JWT,不能用于访问认证
  4. 不能重复使用(可选)

refresh token 获取流程

refresh token 使用流程

代码示例

import jwt
import time

# 使用 sanic 做为restful api 框架 
def create_token(account_id, username):
    payload = {
        "iss": "gusibi.mobi",
        "iat": int(time.time()),
        "exp": int(time.time()) + 86400 * 7,
        "aud": "www.gusibi.mobi",
        "sub": account_id,
        "username": username,
        "scopes": ['open']
    }
    token = jwt.encode(payload, 'secret', algorithm='HS256')
    payload['grant_type'] = "refresh"
    refresh_token = jwt.encode(payload, 'secret', algorithm='HS256')
    return True, {
        'access_token': token,
        'account_id': account_id,
        "refresh_token": refresh_token
        }

# 验证refresh token 出否有效
def verify_refresh_token(token):
    payload = jwt.decode(token, 'secret', audience='www.gusibi.com', algorithms=['HS256'])
    # 校验token 是否有效,以及是不是refresh token,验证经过后生成新的token 以及 refresh_token
    if payload and payload.get('grant_type') == 'refresh':
        # 若是须要标记此token 已经使用,须要借助redis 或者数据库(推荐redis)
        return True, payload
    return False, None

# 验证token 是否有效
def verify_bearer_token(token):
    #  若是在生成token的时候使用了aud参数,那么校验的时候也须要添加此参数
    payload = jwt.decode(token, 'secret', audience='www.gusibi.com', algorithms=['HS256'])
    # 校验token 是否有效,以及不能是refresh token
    if payload and not payload.get('grant_type') == 'refresh':
        return True, payload
    return False, None

参考连接

References
[1] 理解OAuth 2.0: http://www.ruanyifeng.com/blo...设计模式


最后,感谢女友支持和包容,比❤️api

也能够在公号输入如下关键字获取历史文章:公号&小程序 | 设计模式 | 并发&协程跨域

扫码关注

相关文章
相关标签/搜索