必備技能四、ajax及token


https://segmentfault.com/a/1190000008470355?utm_source=tuicool&utm_medium=referral

轉 https://www.jianshu.com/p/576dbf44b2ae

 重要:轉https://www.cnblogs.com/lingnweb/p/9887974.html

vue axios封裝以及登錄token過期跳轉問題  https://blog.csdn.net/H1069495874/article/details/80057107

http://www.51testing.com/html/93/n-4458693-2.html

1.什么是Token 機制?

token的意思是“令牌”,是服務端生成的一串字符串,作為客戶端進行請求的一個標識。 當用戶第一次登錄后,服務器生成一個Token並將此Token返回給客戶端,在以后的請求過程中,需要將該Token作為參數或者放在header里面發送給服務器作為身份驗證的一個步驟,無需再次帶上用戶名和密碼,但是服務端每隔一段時間(比如30分鍾)就會重新生成Token,這時候客戶端再用本地緩存的舊Token去請求就無法通過身份認證,一般狀態碼都會是401。
 

vue項目中token失效處理方法,在main.js配置如下

//判斷token失效跳轉
axios.interceptors.response.use(response => {
    if (response) {
        switch (response.data.code) {

            case 1001: //與后台約定登錄失效的返回碼,根據實際情況處理
                sessionStorage.removeItem('uid');     //刪除用戶ID
                sessionStorage.removeItem('key');     //刪除用戶登錄驗證的key值,即token值
                router.replace({
                    path: '/Login',
                    query: {
                        redirect: router.currentRoute.fullPath
                    }
                })
        }
    }
    return response;
}, error => {

    return Promise.reject(error.response.data) //返回接口返回的錯誤信息
})

token失效后,需用戶重新登錄才可以繼續訪問管理后台 

 

 

 

刷新token和token是否過期的操作都是由后端實現,前端只負責根據code的不同狀態來做不同的操作:

一、判斷token是否過期、失效

舉例:一般響應狀態碼 code :0,表示請求成功。①響應狀態碼 code:10010表示token過期 ②響應狀態碼 code:10011 表示token無效。這些狀態碼都由你自己和后端的同學一起定義。code等於10010和10011這兩種狀態都會跳轉到登錄頁,重新進行登錄並獲取最新的token。

二、在一定時間內刷新token

為什么需要刷新token?因為出於安全性的考慮,一般是一天或幾個小時更新token,看項目需要。

怎么實現?我和后端的同學是這么定義的,在發送任何一次請求時,如果需要更新token,響應體中后端的同學給我返回了token這個字段,token出現在了響應體中,說明這時候是需要刷新token的(其他非刷新token的請求時是沒有token字段的),這時用localStorage保存最新token,自動覆蓋掉原來舊的token,這樣下次再調用新接口時用的就是最新的token了,這樣用戶也感知不到token更新的過程。

    

 

 

三、具體實現

/**
* 全局變量 和 設置 、配置等。。。
*/

import axios from 'axios' // 引入axios

import Storage from '@/assets/js/util/storage.js' // storage工具類,簡單的封裝



axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'



/* 請求攔截器 */

axios.interceptors.request.use(function (config) { // 每次請求時會從localStorage中獲取token

let token = Storage.localGet('token')

if (token) {

token = 'bearer' + ' ' + token.replace(/'|"/g, '') // 把token加入到默認請求參數中

config.headers.common['Authorization'] = token

}

return config

}, function (error) {

return Promise.reject(error)

})

/* 響應攔截器 */

axios.interceptors.response.use(function (response) { // ①10010 token過期(30天) ②10011 token無效

if (response.data.code === 10010 || response.data.code === 10011) {

Storage.localRemove('token') // 刪除已經失效或過期的token(不刪除也可以,因為登錄后覆蓋)

router.replace({

path: '/login' // 到登錄頁重新獲取token

})

} else if (response.data.token) { // 判斷token是否存在,如果存在說明需要更新token

Storage.localSet('token', response.data.token) // 覆蓋原來的token(默認一天刷新一次)

}

return response

}, function (error) {

return Promise.reject(error)

})

緩存工具類 Storage

var Storage = {
// ==================sessionsTorage設置緩存================
// 設置緩存
sessionSet: function (name, data) {
sessionStorage.removeItem(name)
sessionStorage.setItem(name, JSON.stringify(data))
},
// 獲取緩存
sessionGet: function (name) {
return JSON.parse(sessionStorage.getItem(name))
},
// 清除緩存
sessionRemove: function (name) {
sessionStorage.removeItem(name)
},
// ==================localStorage設置緩存==================
// 設置緩存
localSet: function (name, data) {
localStorage.removeItem(name)
localStorage.setItem(name, JSON.stringify(data))
},
// 獲取緩存
localGet: function (name) {
return JSON.parse(localStorage.getItem(name))
},
// 清除緩存
localRemove: function (name) {
localStorage.removeItem(name)
}

}

export default Storage

  

最后,在評論有同學提到並發請求時,因為請求的過程快慢不同,token有可能還是舊的token。所以對於並發請求的情況還是要結合promise來使用

 

 

 

請求時token過期自動刷新token

1.在開發過程中,我們都會接觸到token,token的作用是什么呢?主要的作用就是為了安全,用戶登陸時,服務器會隨機生成一個有時效性的token,用戶的每一次請求都需要攜帶上token,證明其請求的合法性,服務器會驗證token,只有通過驗證才會返回請求結果。

2.當token失效時,現在的網站一般會做兩種處理,一種是跳轉到登陸頁面讓用戶重新登陸獲取新的token,另外一種就是當檢測到請求失效時,網站自動去請求新的token,第二種方式在app保持登陸狀態上面用得比較多。

3.下面進入主題,我們請求用的是axios,不管用何種請求方式,刷新token的原理都是一樣的。

//封裝了一個統一的請求函數,這個不是重點

 

export default function request(url, options) {
    const token = localStorage.getItem('token');
    const defaultOptions = {
        headers: {
            Authorization: `Bearer ${token}`,
        },
        withCredentials: true,
        url: url,
        baseURL: BASE_URL,
    };
    const newOptions = { ...options, ...defaultOptions };
    return axios.request(newOptions)
        .then(checkStatus)
        .catch(error => console.log(error));
}

  

// 封裝了一個檢測返回結果的函數,與后台返回狀態碼code === 1002表示token失效

let isRefreshing = true;
function checkStatus(response) {
  if (response && response.code === 1002) {
    // 刷新token的函數,這需要添加一個開關,防止重復請求
    if(isRefreshing){
        refreshTokenRequst()
    }
    isRefreshing = false;
    // 這個Promise函數很關鍵
      const retryOriginalRequest = new Promise((resolve) => {
                addSubscriber(()=> {
                    resolve(request(url, options))
                })
            });
            return retryOriginalRequest;
  }else{
      return response;
  }
}

  

// 刷新token的請求函數

function refreshTokenRequst(){
    let data;
    const refreshToken = localStorage.getItem('refreshToken');
    data:{
        authorization: 'YXBwYXBpczpaSWxhQUVJdsferTeweERmR1praHk=',
        refreshToken,
    }
    axios.request({
        baseURL: BASE_URL,
        url:'/app/renewal',
        method: 'POST',
        data,
    }).then((response)=>{
        localStorage.setItem('refreshToken',response.data.refreshToken);
        localStorage.setItem('token',response.data.token);
        onAccessTokenFetched();
        isRefreshing = true;
    });
}

  

// Promise函數集合

let subscribers = [];
function onAccessTokenFetched() {
    subscribers.forEach((callback)=>{
        callback();
    })
    subscribers = [];
}

function addSubscriber(callback) {
    subscribers.push(callback)
}

  

總結:其實token失效,自動刷新token,在頁面只有一個請求的時候是比較好處理的,但是如果頁面同時有多個請求,並且都會產生token失效,這就需要一些稍微復雜的處理,解決方式主要是用了Promise 函數來進行處理。每一個token失效的請求都會存到一個Promise函數集合里面,當刷新token的函數執行完畢后,才會批量執行這些Promise函數,返回請求結果。還有一點要注意一下,這兒設置一個刷新token的開關isRefreshing,這個是非常有必要的,防止重復請求。


免責聲明!

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



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