Asp.Net Core中JWT刷新Token解決方案【轉】


一. 前言

1.關於JWT的Token過期問題,到底設置多久過期?

(1).有的人設置過期時間很長,比如一個月,甚至更長,等到過期了退回登錄頁面,重新登錄重新獲取token,期間登錄的時候也是重新獲取token,然后過期時間又重置為了1個月。這樣一旦token被人截取,就可能被人長期使用,如果你想禁止,只能修改token頒發的密鑰,這樣就會導致所有token都失效,顯然不太可取。

(2).有的人設置比較短,比如10分鍾,在使用過程中,一旦過期也是退回登錄頁面,這樣就可能使用過程中經常退回登錄頁面,體驗很不好。

2. 這里介紹一種比較主流的解決方案---雙Token機制

(1).訪問令牌:accessToken,訪問接口是需要攜帶的,也就是我們之前一直使用的那個,過期時間一般設置比較短,根據實際項目分析,比如:10分鍾

(2).刷新令牌:refreshToken,當accessToken過期后,用於獲取新的accessToken的時候使用,過期時間一般設置的比較長,比如:7天

3.獲取新的accessToken的時候, 為什么還需要傳入舊accessToken,只傳入refreshToken不行么?

 仔細看下面的解決思路,只傳入refreshToken也可以,但是傳入雙Token安全性更高一些。

 

二. 解決方案

1. 登錄請求過來,將userId和userAccount存到payLoad中,設置不同的過期時間,分別生成accessToken和refreshToken,二者的區別密鑰不一樣,過期時間不一樣,然后把 生成refreshToken的相關信息存到對應的表中【id,userId,token,expire】,一個用戶對應一條記錄(也可以存到Redis中,這里為了測試,存在一個全局變量中), 每次登錄的時候,添加或者更新記錄,最后將雙Token返回給前端,前端存到LocalStorage中。

 

2. 前端訪問GetMsg獲取信息接口,表頭需要攜帶accessToken,服務器端通過JwtCheck2過濾器進行校驗,驗證通過則正常訪問,如果不通過返回401和不通過的原因,前端在Error中進行獲取,這里區分造成401的原因。

復制代碼
 1 //獲取信息接口
 2         function GetMsg() {
 3             var accessToken = window.localStorage.getItem("accessToken");      
 4             $.ajax({
 5                 url: "/Home/GetMsg",
 6                 type: "Post",
 7                 data: {},
 8                 datatype: "json",
 9                 beforeSend: function (xhr) {
10                     xhr.setRequestHeader("Authorization", "Bearer " + accessToken);
11                 },
12                 success: function (data) {
13                     if (data.status == "ok") {
14                         alert(data.msg);
15                     } else {
16                         alert(data.msg);
17                     }
18                 },
19                 //當安全校驗未通過的時候進入這里
20                 error: function (xhr) {
21                     if (xhr.status == 401) {
22                         var errorMsg = xhr.responseText;
23                         console.log(errorMsg);
24                         //alert(errorMsg);
25                         if (errorMsg == "expired") {
26                             //表示過期,需要自動刷新
27                             GetTokenAgain(GetMsg);
28                         } else {
29                             //表示是非法請求,給出提示,可以直接退回登錄頁
30                             alert("非法請求");
31                         }
32                     }
33                 }
34             });
35         }
復制代碼

3. 如果是表頭為空、校驗錯誤等等,則直接提示請求非法,返回登錄頁。

4. 如果捕獲的是expired即過期,則調用GetTokenAgain(func)方法,即重新獲取accessToken和refreshToken,這里func代表傳遞進來一個方法名,以便調用成功后重新調用原方法,實現無縫刷新; 向服務器端傳遞 雙Token, 服務器端的驗證邏輯如下:

(1). 先通過純代碼校驗refreshToken的物理合法性,如果非法,前端直接報錯,返回到登錄頁面。

(2). 從accessToken中解析出來userId等其它數據(即使accessToken已經過期,依舊可以解析出來)

(3). 拿着userId、refreshToken、當前時間去RefreshToken表中查數據,如果查不到,直接返回前端保存,返回到登錄頁面。

(4). 如果能查到,重新生成 accessToken和refreshToken,並寫入RefreshToken表

(5). 向前端返回雙token,前端進行覆蓋存儲,然后自動調用原方法,攜帶新的accessToken,進行訪問,從而實現無縫刷新token的問題。

復制代碼
 1  //重新獲取訪問令牌和刷新令牌
 2         function GetTokenAgain(func) {
 3             var model = {
 4                 accessToken: window.localStorage.getItem("accessToken"),
 5                 refreshToken: window.localStorage.getItem("refreshToken")
 6             };
 7             $.ajax({
 8                 url: '/Home/UpdateAccessToken',
 9                 type: "POST",
10                 dataType: "json",
11                 data: model,
12                 success: function (data) {
13                     if (data.status == "error") {
14                         debugger;
15                         // 表示重新獲取令牌失敗,可以退回登錄頁
16                         alert("重新獲取令牌失敗");
17 
18                     } else {
19                         window.localStorage.setItem("accessToken", data.data.accessToken);
20                         window.localStorage.setItem("refreshToken", data.data.refreshToken);
21                         func();
22                     }
23                 }
24             });
復制代碼

PS:以上方案,適用於單個頁面發送單個ajax請求,如果是多個請求,有順序的發送,比如第一個發送完,然后再發送第二個,這種場景是沒問題的。

但是,特殊情況如果一個頁面多個ajax並行的過來了,如果其中有一個accessToken過期了,那么它會走更新token的機制,這時候refreshToken和accessToken都更新了(數據庫中refreshToken也更新了),會導致剛才同時進來的其它ajax的refreshToken驗證不過,從而無法刷新雙token。

針對這種特殊情況,作為取舍,更新accessToken的方法中,不更新refreshToken, 那么refreshToken過期,本來也是要進入 登錄頁的,所以針對這類情況,這種取舍也無可厚非。

 

 轉:https://www.cnblogs.com/yaopengfei/p/12449213.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM