文件名稱 | 版本號 | 作者 | 版本 | |
---|---|---|---|---|
OAuth2.0刷新Token | v1.0.0 | 學生宮布 | 8416837 | SpringBoot 2.2.6 SpringCloud Hoxton.SR4 |
需求
- 保證頁面不會在正在操作中卻彈出Token過期,這樣體驗不好。除非好久(設定的閾值)沒有操作頁面了,顯示已過期才合理。
假設你已經搭建好OAuth2.0服務器
- 登錄(授權)成功後,響應數據長這個樣子:
名詞 | 釋義 | 備註 |
---|---|---|
access_token | 作爲消費服務的通行證,逾期會失效 | |
refresh_token | 用來換取新的access_token,會失效,但一般應該設置比access_token晚些失效 | |
expires_in | 多久過期(秒) | 可在數據庫設置或者在令牌管理器代碼設置 |
- 但如果正在操作中,令牌(通行證)突然到期失效了,那多尷尬
- 因此需要在即將過期或已經過期的時候,刷新Token。——前提是refresh_token沒有過期且合法。
解決辦法
- 前提:可以成功獲取Token,併成功在客戶端維護Token、過期時間
1)定時器
- 原理 計算Token過期的時間點,開始計時,噹噹前時間點接近過期點的時候,執行刷新Token操作。要保證每個頁面都可能觸發計時器,且只能有一個,當頁面刷新時,計時器不受影響。
- 代碼 節選
// 從存儲獲取過期時間
computed: mapGetters(['userInfo', 'isLock', 'isCollapse', 'website', 'expires_in']),
... ...
// 這裏是aJax請求攔截器
// 如果即將過期,則調用刷新API,參數是refresh_token, grant_type:授權類型,即refresh_token, scope;並鎖住刷新接口
if (this.expires_in <= 1000 && !this.refreshLock) {
this.refreshLock = true
this.$store
.dispatch('RefreshToken')
.catch(() => {
clearInterval(this.refreshTime)
});
this.refreshLock = false
}
// expires_in遞減
this.$store.commit("SET_EXPIRES_IN", this.expires_in - 10);
... ...
this.$store.dispatch('RefreshToken')
:調用刷新 API
2)請求攔截式,每次請求權限接口都判斷是否可以刷新Token了
- 代碼 節選
// 這裏是aJax請求攔截器
window.isRefreshing = false
... ...
// futureTime:Token在將來某個時間點過期
if (!window.isRefreshing && futureTime && (futureTime - new Date().getTime() ) <= EXPIRED_IN_THIS_SECONDS ) { // 如果expires_in_time eq 0,則很可能是初次登陸,從而勿須刷新令牌 假如設置還差6秒過期
// 鎖 避免多個調用重複刷新
window.isRefreshing = true
// 刷新Token
如果同時調用多個接口,而此時Token已經過期,但refresh_token沒有過期的話,最先刷新的接口可以執行成功,另外的接口不會刷新,會導致請求失敗。但是之後會正常,因爲已經刷新了。見下圖: