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

也能夠在公號輸入如下關鍵字獲取歷史文章:公號&小程序 | 設計模式 | 併發&協程跨域

掃碼關注

相關文章
相關標籤/搜索