中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

token 機制的實現原理是什么

發布時間:2020-12-15 15:20:38 來源:億速云 閱讀:1000 作者:Leah 欄目:開發技術

這期內容當中小編將會給大家帶來有關token 機制的實現原理是什么,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

什么是 token

token 直譯就是令牌的意思,其實就是后端將用戶信息進行非對稱加密,然后將加密后的內容保存在前端,當發送請求的時候帶上這個令牌來實現身份驗證。大致的過程是第一次登錄用戶輸入用戶名和密碼,服務器驗證無誤后會對用戶的信息進行非對稱加密生成一個令牌返回給前端,前端可以存入 cookie 或者 localStorage 等,以后每次發送請求帶上這個令牌,后端通過對令牌的驗證來識別用戶的身份以及請求的合法性。

token 的優點是服務端不需要保存 token,只需要驗證前端傳過來的 token 即可,所以幾遍是分布式部署也可以使用這種方式。token 的缺點就是,由于服務器不保存 session 狀態,因此無法在使用過程中廢止某個 token,或者更改 token 的權限。也就是說,一旦 token 簽發了,在到期之前就會始終有效,除非服務器部署額外的邏輯。

目前比較常用的 token 加密方式是 JWT JSON Web Token,關于 JWT 可以參考阮一峰老師的 JSON Web Token 入門教程

token 刷新

按照上面的 token 邏輯,前端只要保存一個后端傳過來的 token,每次請求附上即可。當令牌過期有兩種選擇,我們可以讓用戶沖洗你登錄,或者后端生成一個新的令牌,前端保存新的令牌并重新發送請求。但是這兩種方式都有問題,如果讓用戶重新登錄,用戶體驗不是很好,頻繁的重新登錄并不是一種比較好的交互方式。而如果自動生成新的令牌則會出現安全問題,比如黑客獲取了一個過期的令牌并向后端發送請求,則也可以獲得一個更新的令牌。

為了權衡上面的問題,產生了一種刷新 token 的機制,當用戶第一次登錄成功,后端會返回兩個 token,一個 accessToken 用來進行請求,也就是我們每次請求都附上 accessToken,而 refreshToken 則是用來在 accessToken 過期的時候進行 accessToken 的刷新。一般來說,accessToken 由于每次請求都會附上,所以安全風險比較高,所以過期時間較短,而 refreshToken 則只有在 accessToken 過期的時候才會發送到后端,所以安全風險相對較低,所以過期時間可以長一點。

當我們的 accessToken 過期之后,我們會向后端的 token 刷新接口請求并傳入 refreshToken,后端驗證梅雨問題之后會給我們一個新的 accessToken,我們保存后就可以保證訪問的連續性。當然,這也并非絕對安全的,只是一種相對安全一點的做法。一般我們將兩個 token 保存在 localStorage 中。

刷新 token 的實現

在項目中我主要使用的是 axios,所以 token 的刷新以及請求附帶 token 都是使用的 axios 的攔截器完成的。這其中需要注意的地方有三點:

  1. 不要重復刷新 token,即一個請求已經刷新 token 了,此時可能新的 token 還沒有回來,其他請求不應該重復刷新。

  2. 當新的 token 還沒有回來的時候,其他的請求應該進行暫存,等新的 token 回來以后再一次進行請求。

  3. 如果請求是由登錄頁面或者請求本身就是刷新 token 的請求則不需要攔截,否則會陷入死循環。

第一個問題用一個 Boolean 字段加鎖即可,第二個問題將請求新 token 過程中發起的請求用狀態為 pendding 的 Promise 進行暫存,放到一個數組中,當新的 token 回來的時候依次 resolve 每一個 pendding 的 Promise 即可。具體的代碼細節我直接貼上項目上的源碼:

import axios, * as AxiosInterface from 'axios';

// Token 接口,訪問 token,刷新 token 和過期時
const instance = axios.create({
 // baseURL: ''
 timeout: 300000,
 headers: {
  'Content-Type': 'application/json',
  'X-Requested-With': 'XMLHttpRequest',
 },
});

async function refreshAccessToken(): Promise<AxiosInterface.AxiosResponse<AxiosData>> {
 return await instance.post('api/refreshtoken');
}

let isRefreshing = false;
let requests: Array<Function> = []; // 若在 token 刷新過程中進來多個請求則存入 requests 中
// axios.defaults.baseURL = 'http://127.0.0.1:8888/api/private/v1/';
// 設置請求攔截器,若 token 過期則刷新 token
axios.interceptors.request.use(config => {
 const tokenObj = JSON.parse(window.localStorage.getItem('token') as string);
 if (config.url === 'api/login' || config.url === 'api/refreshtoken') return config;
 let accessToken = tokenObj.accessToken;
 let expireTime = tokenObj.expireTime;
 const refreshToken = tokenObj.refreshToken;

 config.headers.Authorization = accessToken;

 let time = Date.now();
 console.log(time, expireTime);
 if (time > expireTime) {
  if (!isRefreshing) {
   isRefreshing = true;
   refreshAccessToken()
    .then(res => {
     ({ accessToken, expireTime } = res.data.data);
     time = Date.now();
     const tokenStorage = {
      accessToken,
      refreshToken,
      expireTime: Number(time) + Number(expireTime),
     };
     window.localStorage.setItem('token', JSON.stringify(tokenStorage));
     isRefreshing = false;
     return accessToken;
    })
    .then((accessToken: string) => {
     requests.forEach(cb => {
      cb(accessToken);
     });
     requests = [];
    })
    .catch((err: string) => {
     throw new Error(`refresh token error: {err}`);
    });
  }

  // 如果是在刷新 token 時進行的請求則暫存在 requests 數組中,這里需要使用一個 pendding 的 Promise 來確保攔截的成功
  const parallelRequest: Promise<AxiosInterface.AxiosRequestConfig> = new Promise(resolve => {
   requests.push((accessToken: string) => {
    config.headers.Authorization = accessToken;
    console.log(accessToken + Math.random() * 1000);
    resolve(config);
   });
  });

  return parallelRequest;
 }

 return config;
});

export default (vue: Function) => {
 vue.prototype.http = axios;
};

上述就是小編為大家分享的token 機制的實現原理是什么了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

定州市| 定南县| 莒南县| 光山县| 烟台市| 吐鲁番市| 边坝县| 广丰县| 曲阳县| 水城县| 开原市| 丹巴县| 元朗区| 东辽县| 新乡县| 临城县| 乌拉特后旗| 黄大仙区| 吉林省| 南通市| 彰武县| 嘉定区| 万安县| 宁国市| 井冈山市| 京山县| 明光市| 苏尼特左旗| 徐闻县| 朝阳市| 永川市| 监利县| 专栏| 常德市| 垣曲县| 隆子县| 开化县| 罗江县| 西藏| 京山县| 确山县|