vue的token刷新處理的方法
第一次接觸token處理,初來乍到,說錯的地方還請各位多多指教。
token身份驗證機制
客戶端登錄請求成功后,服務器將用戶信息(如用戶id)使用特殊算法加密后作為驗證的標志發(fā)送給用戶(即token),當用戶下次發(fā)起請求時,會將這個token捎帶過來,服務器再將這個token通過解密后進行驗證,通過的話,則向客戶端返回請求的數(shù)據(jù);反之,則請求失敗。
token優(yōu)點
它是無狀態(tài)的,且服務器不用像傳統(tǒng)的身份認證(session)那樣需要保存會話信息,減輕了服務器的壓力。
vue的token刷新處理
在對token身份驗證機制進行一次簡單介紹后,進入正文...
一般為了安全性,token都會設置一個過期時間,在過期之后就無法請求相關接口了,這時應該怎么辦呢,是直接退出登錄嗎?
在目前公司的項目里,為了更好的用戶體驗,我們選擇手動刷新token。登錄請求成功后,會返回一個token和token過期時間,在每次請求api時,前端可以先判斷一下token是否即將過期或已過期,如果是,則請求刷新token的接口,成功替換原來的token之后才可以重新發(fā)起請求。
下面,我們直接看代碼,這是在vue的請求攔截器里進行的相關操作:
/*是否有請求正在刷新token*/
window.isRefreshing = false
/*被掛起的請求數(shù)組*/
let refreshSubscribers = []
/*獲取刷新token請求的token*/
function getRefreshToken () {
return JSON.parse(localStorage.auth).refresh_token
}
/*push所有請求到數(shù)組中*/
function subscribeTokenRefresh (cb) {
refreshSubscribers.push(cb)
}
/*刷新請求(refreshSubscribers數(shù)組中的請求得到新的token之后會自執(zhí)行,用新的token去請求數(shù)據(jù))*/
function onRrefreshed (token) {
refreshSubscribers.map(cb => cb(token))
}
/*請求攔截器*/
ajax.interceptors.request.use(
config => {
const authTmp = localStorage.auth
/*判斷是否已登錄*/
if (authTmp) {
/*解析登錄信息*/
let auth = JSON.parse(authTmp)
/*判斷auth是否存在*/
if (auth) {
/*在請求頭中添加token類型、token*/
config.headers.Authorization = auth.token_type + ' ' + auth.token
/*判斷刷新token請求的refresh_token是否過期*/
if (util.isRefreshTokenExpired()) {
alert('刷新token過期,請重新登錄')
/*清除本地保存的auth*/
localStorage.removeItem('auth')
window.location.href = '#/login'
return
}
/*判斷token是否將要過期*/
if (util.isTokenExpired() && config.url.indexOf('admin/auth/current') === -1) {
/*判斷是否正在刷新*/
if (!window.isRefreshing) {
/*將刷新token的標志置為true*/
window.isRefreshing = true
/*發(fā)起刷新token的請求*/
apiList.refreshToken({refresh_token: getRefreshToken()}).then(res => {
/*將標志置為false*/
window.isRefreshing = false
/*成功刷新token*/
config.headers.Authorization = res.data.data.token_type + ' ' + res.data.data.token
/*更新auth*/
localStorage.setItem('auth', JSON.stringify(res.data.data))
/*執(zhí)行數(shù)組里的函數(shù),重新發(fā)起被掛起的請求*/
onRrefreshed(res.data.data.token)
/*執(zhí)行onRefreshed函數(shù)后清空數(shù)組中保存的請求*/
refreshSubscribers = []
}).catch(err => {
alert(err.response.data.message)
/*清除本地保存的auth*/
// localStorage.removeItem('auth')
window.location.href = '#/login'
})
}
/*把請求(token)=>{....}都push到一個數(shù)組中*/
let retry = new Promise((resolve, reject) => {
/*(token) => {...}這個函數(shù)就是回調函數(shù)*/
subscribeTokenRefresh((token) => {
config.headers.Authorization = 'Bearer ' + token
/*將請求掛起*/
resolve(config)
})
})
return retry
}
}
return config
} else {
/*未登錄直接返回配置信息*/
return config
}
},
/*錯誤操作*/
err => {
return Promise.reject(err)
}
)
這里需要注意幾點:
1、當token即將過期或者已過期時,原則上,我們只需要有一個接口去觸發(fā)刷新token的請求即可,這里的isRefreshing 變量,就起到這樣一個監(jiān)控的作用,它相當于一把鎖,當刷新token的操作被觸發(fā)后,其他的觸發(fā)操作就被排斥在外了。
window.isRefreshing = false
2、刷新token的接口,用到了一個另外的token(refresh_token),這也是出于安全性考慮的,并且它也有過期時間,不過這個過期時間一般都比普通token的過期時間要長,所以在上面代碼中,會發(fā)現(xiàn),我在請求攔截中優(yōu)先判斷了refresh_token是否過期,如果過期則直接退出登錄,不再進行下一步的操作。
/*判斷刷新token請求的refresh_token是否過期*/
if (util.isRefreshTokenExpired() && config.url.indexOf('admin/auth/current') === -1) {
alert('刷新token過期,請重新登錄')
/*清除本地保存的auth*/
localStorage.removeItem('auth')
window.location.href = '#/login'
return
}
3、在觸發(fā)了刷新token的操作后,我們還需要先將其他的請求掛起,在獲取新的token之后再重新發(fā)起這些請求。
/*把請求(token)=>{....}都push到一個數(shù)組中*/
let retry = new Promise((resolve, reject) => {
/*(token) => {...}這個函數(shù)就是回調函數(shù)*/
subscribeTokenRefresh((token) => {
config.headers.Authorization = 'Bearer ' + token
/*將請求掛起*/
resolve(config)
})
})
return retry
在刷新token請求的成功回調里執(zhí)行下面代碼,重新發(fā)起請求。
/*執(zhí)行數(shù)組里的函數(shù),重新發(fā)起被掛起的請求*/ onRrefreshed(res.data.data.token)
4、因為有人在評論里問util文件,應該是想知道具體怎么判斷token過期的,其實在獲得token時,是有返回一個token過期時間 ,你可以先將它先保存起來,然后在需要時,拿出來與本地時間比較即可
/*判斷token是否過期*/
function isTokenExpired() {
/*從localStorage中取出token過期時間*/
let expiredTime = new Date(JSON.parse(localStorage.auth).expired_at).getTime() / 1000
/*獲取本地時間*/
let nowTime = new Date().getTime() / 1000
/*獲取校驗時間差*/
let diffTime = JSON.parse(sessionStorage.diffTime)
/*校驗本地時間*/
nowTime -= diffTime
/*如果 < 10分鐘,則說明即將過期*/
return (expiredTime - nowTime) < 10*60
}
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
vue結合el-upload實現(xiàn)騰訊云視頻上傳功能
這篇文章主要介紹了vue結合el-upload實現(xiàn)騰訊云視頻上傳功能,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-07-07
vue 內聯(lián)樣式style中的background用法說明
這篇文章主要介紹了vue 內聯(lián)樣式style中的background用法說明,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-08-08
vue深入解析之render function code詳解
vue對大家來說應該再熟悉不過了,下面這篇文章主要給大家深入的解析了vue之render function code的相關資料,文中通過示例代碼介紹的非常詳細,對大家具有一定的參考學習價值,需要的朋友們下面來一起看看吧。2017-07-07
Vue中@click.stop與@click.prevent解讀
Vue中,`@click.stop`用于阻止事件冒泡,而`@click.prevent`用于阻止事件的默認行為,這兩個方法在處理事件時非常有用2025-02-02
詳解Vue3中shallowRef和shallowReactive的使用
這篇文章主要為大家介紹了Vue3中shallowRef和shallowReactive函數(shù)的使用方法,文中的示例代碼講解詳細,對我們學習Vue有一定的幫助,需要的可以參考一下2022-07-07

