基於JWT的token身份認證方案(轉)

https://www.cnblogs.com/xiangkejin/archive/2018/05/08/9011119.htmlhtml

 

1、使用JSON Web Token的好處?

1.性能問題。
JWT方式將用戶狀態分散到了客戶端中,相比於session,能夠明顯減輕服務端的內存壓力。
Session方式存儲用戶id的最大弊病在於Session是存儲在服務器端的,因此須要佔用大量服務器內存,
對於較大型應用而言可能還要保存許多的狀態,通常還需藉助nosql和緩存機制來實現session的存儲,若是是分佈式應用還需session共享。 
2.單點登陸。
JWT能輕鬆的實現單點登陸,由於用戶的狀態已經被傳送到了客戶端。
token 可保存自定義信息,如用戶基本信息,web服務器用key去解析token,就獲取到請求用戶的信息了。
咱們也能夠配置它以便包含用戶擁有的任何權限。這意味着每一個服務不須要與受權服務交互才能受權用戶。
3.先後端分離。
之前的傳統模式下,後臺對應的客戶端就是瀏覽器,就可使用session+cookies的方式實現登陸,
可是在先後分離的狀況下,後端只負責經過暴露的RestApi提供數據,而頁面的渲染、路由都由前端完成。由於rest是無狀態的,所以也就不會有session記錄到服務器端。
4.兼容性。
支持移動設備,支持跨程序調用,Cookie 是不容許垮域訪問的,而 Token 則不存在這個問題。
5.可拓展性。
jwt是無狀態的,特別適用於分佈式站點的單點登陸(SSO)場景。
好比有3臺機器(A、B、C)組成服務器集羣,若session存在機器A上,session只能保存在其中一臺服務器,此時你便不能訪問機器B、C,由於B、C上沒有存放該Session,
而使用token就可以驗證用戶請求合法性,而且我再加幾臺機器也沒事,因此可拓展性好。
6.安全性。由於有簽名,因此JWT能夠防止被篡改。

2、JSON Web Token是什麼?

JWT是基於token的身份認證的方案前端

json web token全稱。能夠保證安全傳輸的前提下傳送一些基本的信息,以減輕對外部存儲的依賴,減小了分佈式組件的依賴,減小了硬件的資源。web

實現無狀態、分佈式的Web應用受權,jwt的安全特性保證了token的不可僞造和不可篡改。redis

本質上是一個獨立的身份驗證令牌,能夠包含用戶標識、用戶角色和權限等信息,以及您能夠存儲任何其餘信息(自包含)。任何人均可以輕鬆讀取和解析,並使用密鑰來驗證真實性。算法

 

缺陷:
1)JWT在生成token的時候支持失效時間,可是支持的失效時間是固定的,好比說一天。
可是用戶在等出的時候是隨機觸發的,那麼咱們jwt token來作這個失效是不可行的,由於jwt在初始化的時候已經定死在何時過時了。
採用其餘方案,在redis中存儲token,設置token的過時時間,每次鑑權的時候都會去延長時間
2)jwt不適合存放大量信息,信息越多token越長

 

JWT就是一個字符串,通過加密處理與校驗處理的字符串,形式爲:sql

    A.B.C數據庫

A由JWT頭部信息header加密獲得
B由JWT用到的身份驗證信息json數據加密獲得
C由A和B加密獲得,是校驗部分json

分別是頭部、載荷、簽名。 
頭部部分header 

「alg」: 「HS256」, 
「typ」: 「JWT」 

alg描述的是簽名算法。默認值是HS256。

將header用base64加密,獲得A。後端

 

載荷部分payload 

「iss」: 「發行者」, 
「sub」: 主題」, 
「aud」: 「觀衆」, 
「exp」:」過時時間」, 
「iat」:」簽發時間」 
如下能夠添加自定義數據 
「id」:」1」, 
「nickname」:」暱稱」 
瀏覽器

根據JWT claim set[用base64]加密獲得的。claim set是一個json數據,是代表用戶身份的數據,可自行指定字段很靈活,也有固定字段表示特定含義(但不必定要包含特定字段,只是推薦)。
Base64算法是可逆的,不能夠在載荷部分保存用戶密碼等敏感信息。若是業務須要,也能夠採用對稱密鑰加密。

 

簽名部分signature 
HMACSHA256(Base64(Header) + 「.」 + Base64(Payload), secret),secret是加密的鹽。
簽名的目的是用來驗證頭部和載荷是否被非法篡改。 
驗簽過程描述:獲取token值,讀取Header部分並Base64解碼,獲得簽名算法。根據以上方法算出簽名,若是簽名信息不一致,說明是非法的。

 

3、JSON Web Token工做原理

  1. 初次登陸:用戶初次登陸,輸入用戶名密碼

  2. 密碼驗證:服務器從數據庫取出用戶名和密碼進行驗證

  3. 生成JWT:服務器端驗證經過,根據從數據庫返回的信息,以及預設規則,生成JWT

  4. 返還JWT:服務器的將token放在cookie中將JWT返還

  5. 帶JWT的請求:之後客戶端發起請求,帶上cookie中的token信息。

 

4、jwt+redis的登陸方案流程:

  • 前端服務器收到用戶登陸請求,傳給後臺API網關。

  • API網關把請求分發到用戶服務裏進行身份驗證。
  • 後臺用戶服務驗證經過,而後從帳號信息抽取出userName、login_time等基本信息組成payload,進而組裝一個JWT,把JWT放入redis(由於退出的時候沒法使jwt當即做廢,因此使用保存在redis中,退出的時候delete掉就能夠了,鑑權的時候加一層判斷jwt是否在redis裏,若是不在則證實jwt已過時做廢),而後包裝cookie中返回到前端服務器,這就登陸成功了。

  • 前端服務器拿到JWT,進行存儲(能夠存儲在緩存中,也能夠存儲在數據庫中,若是是瀏覽器,能夠存儲在 localStorage 中,我實現的是放入到cookie裏面)

  • 登陸後,再訪問其餘微服務的時候,前端會攜帶jwt訪問後臺,後臺校驗 JWT,驗籤經過後,返回相應資源和數據就能夠了。

 

(這裏沒有將redis畫出來)

 

結合攔截器與上篇session-cookie方式的區別:

首次登陸步驟:

1.首先AuthInterceptor攔截器攔截用戶請求,在preHandle中看cookie中是否有token信息,沒有就接着攔截器AuthActionInterceptor攔截須要登陸的url,看threadlocal當中是否有user對象,若是沒有就跳轉到登陸頁面進行登陸,登陸成功後會將user對象放到threadlocal中。(注意這個地方和上篇中提到的登陸成功後將user放到session的不一樣

登陸處理流程:在數據庫中查詢驗證用戶名密碼,經過就講帳號信息抽取出username、email等信息組成一個payload,進而組裝成一個JWT,而後將JWT放到redis當中,設置過時時間。

生成token

給定簽名算法、給定載荷的map、進行簽名

2.當業務邏輯處理完以後在AuthInterceptor的postHandle中,從threadlocal獲取user對象中的token信息,將token放到cookie中返回給前端。

3.請求結束後在AuthInterceptor的afterCompletion將user從threadlocal中移除。

 

驗證流程:

前端將攜帶jwt的cookie傳到後臺,AuthInterceptor會根據token驗證解析出user,(注意根以前在session中取對象的不一樣)驗證後再將user放到threadlocal中,AuthActionInterceptor一看threadlocal有user對象,直接經過。後面的步驟同樣。

驗證token:

1)從token的Header中拿出簽名算法,看和以前生成token的簽名算法是否一致。

2)驗證簽名,獲取載荷map,從中獲取用戶標識email,在redis中看是否失效,若是失效,拋出未登陸錯誤;若是未失效,更新redis的失效時間,返回用戶的信息。

AuthInterceptor

  View Code

AuthActionInterceptor

  View Code

 UserService

  View Code

 JWTHelper

  View Code
相關文章
相關標籤/搜索