Vue3+Vite怎麼使用雙token實(shí)現(xiàn)無(wú)感刷新
May 10, 2023 pm 01:10 PM一、token 登入鑑權(quán)
jwt:JSON Web Token。是一種認(rèn)證協(xié)議,一般用來(lái)校驗(yàn)請(qǐng)求的身份資訊和身分權(quán)限。由三個(gè)部分組成:Header、Hayload、Signature
header:也就是頭部訊息,是描述這個(gè)token 的基本訊息,json 格式
{ "alg": "HS256", // 表示簽名的算法,默認(rèn)是 HMAC SHA256(寫(xiě)成 HS256) "type": "JWT" // 表示Token的類型,JWT 令牌統(tǒng)一寫(xiě)為JWT }
payload:載荷,也是一個(gè)JSON 對(duì)象,用來(lái)存放實(shí)際需要傳遞的資料。不建議存放敏感資訊,例如密碼。
{ "iss": "a.com", // 簽發(fā)人 "exp": "1d", // expiration time 過(guò)期時(shí)間 "sub": "test", // 主題 "aud": "", // 受眾 "nbf": "", // Not Before 生效時(shí)間 "iat": "", // Issued At 簽發(fā)時(shí)間 "jti": "", // JWT ID 編號(hào) // 可以定義私有字段 "name": "", "admin": "" }
Signature 簽名 是對(duì)前兩部分的簽名,防止資料被竄改。需要指定一個(gè)密鑰。這個(gè)密鑰只有伺服器才知道,不能外洩。使用 Header 裡面指定的簽名演算法,依照公式產(chǎn)生簽名。
算出簽名後,把 Header、Payload、Signature 三個(gè)部分拼成的一個(gè)字串,每個(gè)部分之間用 . 分隔。這樣就產(chǎn)生了一個(gè)token
二、何為雙token
#accessToken
:使用者取得資料權(quán)限
- #refreshToken
:用來(lái)取得新的accessToken
雙token 驗(yàn)證機(jī)制,其中accessToken 過(guò)期時(shí)間較短,refreshToken 過(guò)期時(shí)間較長(zhǎng)。當(dāng) accessToken 過(guò)期後,使用 refreshToken 去請(qǐng)求新的 token。
雙 token 驗(yàn)證流程
- 使用者登入向服務(wù)端傳送帳號(hào)密碼,登入失敗傳回客戶端重新登入。登入成功服務(wù)端產(chǎn)生 accessToken 和 refreshToken,傳回產(chǎn)生的 token 給客戶端。
- 在請(qǐng)求攔截器中,請(qǐng)求頭中攜帶 accessToken 請(qǐng)求數(shù)據(jù),服務(wù)端驗(yàn)證 accessToken 是否過(guò)期。 token 有效繼續(xù)請(qǐng)求數(shù)據(jù),token 失效返回失效訊息到客戶端。
- 客戶端收到服務(wù)端發(fā)送的請(qǐng)求訊息,在二次封裝的 axios 的回應(yīng)攔截器中判斷是否有 accessToken 失效的訊息,沒(méi)有回傳回應(yīng)的資料。有失效的訊息,就攜帶 refreshToken 請(qǐng)求新的 accessToken。
服務(wù)端驗(yàn)證 refreshToken 是否有效。有效,重新產(chǎn)生 token, 傳回新的 token 和提示訊息到客戶端,無(wú)效,傳回?zé)o效訊息給客戶端。
客戶端回應(yīng)攔截器判斷回應(yīng)訊息是否有 refreshToken 有效無(wú)效。無(wú)效,登出目前登入。有效,重新儲(chǔ)存新的 token,繼續(xù)請(qǐng)求上一次要求的資料。
注意事項(xiàng)
短token失效,服務(wù)端拒絕請(qǐng)求,返回token失效訊息,前端請(qǐng)求到新的短token如何再次請(qǐng)求數(shù)據(jù),達(dá)到無(wú)感刷新的效果。
服務(wù)端白名單,成功登入前是還沒(méi)有請(qǐng)求到token的,那麼如果服務(wù)端攔截請(qǐng)求,就無(wú)法登入??脱u化白名單,讓登入無(wú)需進(jìn)行token驗(yàn)證。
三、服務(wù)端程式碼
#1. 建立koa2伺服器
全域安裝koa腳手架
npm install koa-generator -g
建立服務(wù)端直接koa2專案名稱
koa2 server
cd server 進(jìn)入到專案安裝jwt
npm i jsonwebtoken
為了方便直接在服務(wù)端使用koa-cors 跨網(wǎng)域
npm i koa-cors在app.js中引入應(yīng)用程式cors
const cors=require('koa-cors')
...
app.use(cors())
2. 雙token新utils/token.jsconst jwt=require('jsonwebtoken') const secret='2023F_Ycb/wp_sd' // 密鑰 /* expiresIn:5 過(guò)期時(shí)間,時(shí)間單位是秒 也可以這么寫(xiě) expiresIn:1d 代表一天 1h 代表一小時(shí) */ // 本次是為了測(cè)試,所以設(shè)置時(shí)間 短token5秒 長(zhǎng)token15秒 const accessTokenTime=5 const refreshTokenTime=15 // 生成accessToken const setAccessToken=(payload={})=>{ // payload 攜帶用戶信息 return jwt.sign(payload,secret,{expireIn:accessTokenTime}) } //生成refreshToken const setRefreshToken=(payload={})=>{ return jwt.sign(payload,secret,{expireIn:refreshTokenTime}) } module.exports={ secret, setAccessToken, setRefreshToken }3. 路由直接使用腳手架建立的專案已經(jīng)在app.js使用了路由中間件在router/index.js 建立介面
const router = require('koa-router')()
const jwt = require('jsonwebtoken')
const { getAccesstoken, getRefreshtoken, secret }=require('../utils/token')
/*登錄接口*/
router.get('/login',()=>{
let code,msg,data=null
code=2000
msg='登錄成功,獲取到token'
data={
accessToken:getAccessToken(),
refreshToken:getReferToken()
}
ctx.body={
code,
msg,
data
}
})
/*用于測(cè)試的獲取數(shù)據(jù)接口*/
router.get('/getTestData',(ctx)=>{
let code,msg,data=null
code=2000
msg='獲取數(shù)據(jù)成功'
ctx.body={
code,
msg,
data
}
})
/*驗(yàn)證長(zhǎng)token是否有效,刷新短token
這里要注意,在刷新短token的時(shí)候回也返回新的長(zhǎng)token,延續(xù)長(zhǎng)token,
這樣活躍用戶在持續(xù)操作過(guò)程中不會(huì)被迫退出登錄。長(zhǎng)時(shí)間無(wú)操作的非活
躍用戶長(zhǎng)token過(guò)期重新登錄
*/
router.get('/refresh',(ctx)=>{
let code,msg,data=null
//獲取請(qǐng)求頭中攜帶的長(zhǎng)token
let r_tk=ctx.request.headers['pass']
//解析token 參數(shù) token 密鑰 回調(diào)函數(shù)返回信息
jwt.verify(r_tk,secret,(error)=>{
if(error){
code=4006,
msg='長(zhǎng)token無(wú)效,請(qǐng)重新登錄'
} else{
code=2000,
msg='長(zhǎng)token有效,返回新的token',
data={
accessToken:getAccessToken(),
refreshToken:getReferToken()
}
}
})
})
4. 應(yīng)用中間件utils/auth.jsconst { secret } = require('./token')
const jwt = require('jsonwebtoken')
/*白名單,登錄、刷新短token不受限制,也就不用token驗(yàn)證*/
const whiteList=['/login','/refresh']
const isWhiteList=(url,whiteList)=>{
return whiteList.find(item => item === url) ? true : false
}
/*中間件
驗(yàn)證短token是否有效
*/
const cuth = async (ctx,next)=>{
let code, msg, data = null
let url = ctx.path
if(isWhiteList(url,whiteList)){
// 執(zhí)行下一步
return await next()
} else {
// 獲取請(qǐng)求頭攜帶的短token
const a_tk=ctx.request.headers['authorization']
if(!a_tk){
code=4003
msg='accessToken無(wú)效,無(wú)權(quán)限'
ctx.body={
code,
msg,
data
}
} else{
// 解析token
await jwt.verify(a_tk,secret.(error)=>{
if(error)=>{
code=4003
msg='accessToken無(wú)效,無(wú)權(quán)限'
ctx.body={
code,
msg,
datta
}
} else {
// token有效
return await next()
}
})
}
}
}
module.exports=auth
在app.js中引入應(yīng)用中間件const auth=requier(./utils/auth) ··· app.use(auth)其實(shí)如果只是做一個(gè)簡(jiǎn)單的雙token驗(yàn)證,很多中間件是沒(méi)必要的,例如解析靜態(tài)資源。不過(guò)為了節(jié)省時(shí)間,方便就直接使用了koa2鷹架。 最終目錄結(jié)構(gòu):
四、前端程式碼
1. Vue3 Vite框架
#前端使用了Vue3 Vite的框架,看個(gè)人使用習(xí)慣。
npm init vite@latest client_side
安裝axios
npm i axios2. 定義使用到的常數(shù)config/constants.js
export const ACCESS_TOKEN = 'a_tk' // 短token字段 export const REFRESH_TOKEN = 'r_tk' // 短token字段 export const AUTH = 'Authorization' // header頭部 攜帶短token export const PASS = 'pass' // header頭部 攜帶長(zhǎng)token

export {REFRESH_TOKEN,PASS} from '../config/constants.js' import { getRefreshToken, removeRefreshToken, setAccessToken, setRefreshToken} from '../config/storage' let subsequent=[] let flag=false // 設(shè)置開(kāi)關(guān),保證一次只能請(qǐng)求一次短token,防止客戶多此操作,多次請(qǐng)求 /*把過(guò)期請(qǐng)求添加在數(shù)組中*/ export const addRequest = (request) => { subscribes.push(request) } /*調(diào)用過(guò)期請(qǐng)求*/ export const retryRequest = () => { console.log('重新請(qǐng)求上次中斷的數(shù)據(jù)'); subscribes.forEach(request => request()) subscribes = [] } /*短token過(guò)期,攜帶token去重新請(qǐng)求token*/ export const refreshToken=()=>{ if(!flag){ flag = true; let r_tk = getRefershToken() // 獲取長(zhǎng)token if(r_tk){ server.get('/refresh',Object.assign({},{ headers:{[PASS]=r_tk} })).then((res)=>{ //長(zhǎng)token失效,退出登錄 if(res.code===4006){ flag = false removeRefershToken(REFRESH_TOKEN) } else if(res.code===2000){ // 存儲(chǔ)新的token setAccessToken(res.data.accessToken) setRefreshToken(res.data.refreshToken) flag = false // 重新請(qǐng)求數(shù)據(jù) retryRequest() } }) } } }###4. 封裝 axios######utlis/server.js###
import axios from "axios"; import * as storage from "../config/storage" import * as constants from '../config/constants' import { addRequest, refreshToken } from "./refresh"; const server = axios.create({ baseURL: 'http://localhost:3004', // 你的服務(wù)器 timeout: 1000 * 10, headers: { "Content-type": "application/json" } }) /*請(qǐng)求攔截器*/ server.interceptors.request.use(config => { // 獲取短token,攜帶到請(qǐng)求頭,服務(wù)端校驗(yàn) let aToken = storage.getAccessToken(constants.ACCESS_TOKEN) config.headers[constants.AUTH] = aToken return config }) /*響應(yīng)攔截器*/ server.interceptors.response.use( async response => { // 獲取到配置和后端響應(yīng)的數(shù)據(jù) let { config, data } = response console.log('響應(yīng)提示信息:', data.msg); return new Promise((resolve, reject) => { // 短token失效 if (data.code === 4003) { // 移除失效的短token storage.removeAccessToken(constants.ACCESS_TOKEN) // 把過(guò)期請(qǐng)求存儲(chǔ)起來(lái),用于請(qǐng)求到新的短token,再次請(qǐng)求,達(dá)到無(wú)感刷新 addRequest(() => resolve(server(config))) // 攜帶長(zhǎng)token去請(qǐng)求新的token refreshToken() } else { // 有效返回相應(yīng)的數(shù)據(jù) resolve(data) } }) }, error => { return Promise.reject(error) } )###5. 復(fù)用封裝###
import * as constants from "./constants" // 存儲(chǔ)短token export const setAccessToken = (token) => localStorage.setItem(constanst.ACCESS_TOKEN, token) // 存儲(chǔ)長(zhǎng)token export const setRefershToken = (token) => localStorage.setItem(constants.REFRESH_TOKEN, token) // 獲取短token export const getAccessToken = () => localStorage.getItem(constants.ACCESS_TOKEN) // 獲取長(zhǎng)token export const getRefershToken = () => localStorage.getItem(constants.REFRESH_TOKEN) // 刪除短token export const removeAccessToken = () => localStorage.removeItem(constants.ACCESS_TOKEN) // 刪除長(zhǎng)token export const removeRefershToken = () => localStorage.removeItem(constants.REFRESH_TOKEN)###6. 介面封裝######apis/index.js###
import server from "../utils/server"; /*登錄*/ export const login = () => { return server({ url: '/login', method: 'get' }) } /*請(qǐng)求數(shù)據(jù)*/ export const getData = () => { return server({ url: '/getList', method: 'get' }) }###專案運(yùn)行################最後的最後,執(zhí)行項(xiàng)目,查看效果後端設(shè)定的短token5秒,長(zhǎng)token10秒。登入請(qǐng)求到token後,請(qǐng)求資料可以正常請(qǐng)求,五秒後再次請(qǐng)求,短token失效,這時(shí)長(zhǎng)token有效,請(qǐng)求到新的token,refresh介面只呼叫了一次。長(zhǎng)token也過(guò)期後,就需要重新登入啦。 ############
以上是Vue3+Vite怎麼使用雙token實(shí)現(xiàn)無(wú)感刷新的詳細(xì)內(nèi)容。更多資訊請(qǐng)關(guān)注PHP中文網(wǎng)其他相關(guān)文章!

熱AI工具

Undress AI Tool
免費(fèi)脫衣圖片

Undresser.AI Undress
人工智慧驅(qū)動(dòng)的應(yīng)用程序,用於創(chuàng)建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費(fèi)的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門(mén)文章

熱工具

記事本++7.3.1
好用且免費(fèi)的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強(qiáng)大的PHP整合開(kāi)發(fā)環(huán)境

Dreamweaver CS6
視覺(jué)化網(wǎng)頁(yè)開(kāi)發(fā)工具

SublimeText3 Mac版
神級(jí)程式碼編輯軟體(SublimeText3)

Vue3+TS+Vite開(kāi)發(fā)技巧:如何進(jìn)行SEO優(yōu)化SEO(SearchEngineOptimization)是指透過(guò)優(yōu)化網(wǎng)站的結(jié)構(gòu)、內(nèi)容和關(guān)鍵字等方面,使其在搜尋引擎的排名更靠前,從而增加網(wǎng)站的流量和曝光度。在Vue3+TS+Vite等現(xiàn)代前端技術(shù)的開(kāi)發(fā)中,如何進(jìn)行SEO最佳化是一個(gè)很重要的問(wèn)題。本文將介紹一些Vue3+TS+Vite開(kāi)發(fā)的技巧與方法,幫

登入token無(wú)效問(wèn)題可以透過(guò)檢查網(wǎng)路連線、檢查token有效期、清除快取和Cookie、檢查登入狀態(tài)、聯(lián)絡(luò)應(yīng)用程式開(kāi)發(fā)者和加強(qiáng)帳號(hào)安全來(lái)解決。詳細(xì)介紹:1、檢查網(wǎng)路連接,重新連接網(wǎng)路或更換網(wǎng)路環(huán)境;2、檢查token有效期,重新取得一個(gè)新的token,或聯(lián)絡(luò)應(yīng)用程式的開(kāi)發(fā)者;3、清除快取和Cookie,清除瀏覽器快取和Cookie,然後重新登入應(yīng)用程式;4、檢查登入狀態(tài)。

登入token無(wú)效的解決辦法有檢查T(mén)oken是否過(guò)期、檢查T(mén)oken是否正確、檢查T(mén)oken是否被篡改、檢查T(mén)oken是否與使用者匹配、清除快取或Cookie、檢查網(wǎng)路連線和伺服器狀態(tài)、重新登入或請(qǐng)求新的Token、聯(lián)絡(luò)技術(shù)支援或開(kāi)發(fā)人員等。詳細(xì)介紹:1、檢查T(mén)oken是否過(guò)期,登入Token通常會(huì)設(shè)定有效期,一旦超過(guò)有效期,就會(huì)被認(rèn)為無(wú)效等等。

想要實(shí)現(xiàn)頁(yè)面的局部刷新,我們只需要實(shí)現(xiàn)局部元件(dom)的重新渲染。在Vue中,想要實(shí)現(xiàn)這效果最簡(jiǎn)單的方式方法就是使用v-if指令。在Vue2中我們除了使用v-if指令讓局部dom的重新渲染,也可以新建一個(gè)空白元件,需要刷新局部頁(yè)面時(shí)跳轉(zhuǎn)至這個(gè)空白元件頁(yè)面,然後在空白元件內(nèi)的beforeRouteEnter守衛(wèi)中又跳轉(zhuǎn)回原來(lái)的頁(yè)面。如下圖所示,如何在Vue3.X中實(shí)現(xiàn)點(diǎn)擊刷新按鈕實(shí)現(xiàn)紅框範(fàn)圍內(nèi)的dom重新加載,並展示對(duì)應(yīng)的加載狀態(tài)。由於Vue3.X中scriptsetup語(yǔ)法中組件內(nèi)守衛(wèi)只有o

Vue3+TS+Vite開(kāi)發(fā)技巧:如何進(jìn)行前端安全防護(hù)隨著前端技術(shù)的不斷發(fā)展,越來(lái)越多的企業(yè)和個(gè)人開(kāi)始使用Vue3+TS+Vite進(jìn)行前端開(kāi)發(fā)。然而,隨之而來(lái)的安全風(fēng)險(xiǎn)也引起了人們的注意。在本文中,我們將探討一些常見(jiàn)的前端安全性問(wèn)題,並分享一些在Vue3+TS+Vite開(kāi)發(fā)過(guò)程中如何進(jìn)行前端安全防護(hù)的技巧。輸入驗(yàn)證使用者的輸入往往是前端安全漏洞的主要來(lái)源之一。在

Vue3+TS+Vite開(kāi)發(fā)技巧:如何進(jìn)行資料加密和儲(chǔ)存隨著網(wǎng)路技術(shù)的快速發(fā)展,資料的安全性和隱私保護(hù)變得越來(lái)越重要。在Vue3+TS+Vite開(kāi)發(fā)環(huán)境下,如何進(jìn)行資料加密和存儲(chǔ),是每個(gè)開(kāi)發(fā)人員都需要面對(duì)的問(wèn)題。本文將介紹一些常用的資料加密和儲(chǔ)存的技巧,幫助開(kāi)發(fā)人員提升應(yīng)用程式的安全性和使用者體驗(yàn)。一、資料加密前端資料加密前端加密是保護(hù)資料安全性的重要一環(huán)。常用

Vue3+TS+Vite開(kāi)發(fā)技巧:如何進(jìn)行跨域請(qǐng)求和網(wǎng)路請(qǐng)求最佳化引言:在前端開(kāi)發(fā)中,網(wǎng)路請(qǐng)求是非常常見(jiàn)的操作。如何優(yōu)化網(wǎng)頁(yè)請(qǐng)求以提高頁(yè)面載入速度和使用者體驗(yàn)是我們開(kāi)發(fā)者需要思考的問(wèn)題之一。同時(shí),對(duì)於一些需要向不同網(wǎng)域發(fā)送請(qǐng)求的場(chǎng)景,我們需要解決跨域問(wèn)題。本文將介紹如何在Vue3+TS+Vite開(kāi)發(fā)環(huán)境下進(jìn)行跨域請(qǐng)求以及網(wǎng)路請(qǐng)求的最佳化技巧。一、跨域請(qǐng)求解決方案使

最終效果安裝VueCropper組件yarnaddvue-cropper@next上面的安裝值針對(duì)Vue3的,如果時(shí)Vue2或想使用其他的方式引用,請(qǐng)?jiān)L問(wèn)它的npm官方地址:官方教程。在元件中引用使用時(shí)也很簡(jiǎn)單,只需要引入對(duì)應(yīng)的元件和它的樣式文件,我這裡沒(méi)有在全域引用,只在我的元件檔案中引入import{userInfoByRequest}from'../js/api' import{VueCropper}from'vue-cropper&
