Vue3+Vite怎麼使用雙token實現無感刷新
一、token 登入鑑權
jwt:JSON Web Token。是一種認證協議,一般用來校驗請求的身份資訊和身分權限。由三個部分組成:Header、Hayload、Signature
header:也就是頭部訊息,是描述這個token 的基本訊息,json 格式
{ "alg": "HS256", // 表示签名的算法,默认是 HMAC SHA256(写成 HS256) "type": "JWT" // 表示Token的类型,JWT 令牌统一写为JWT }
payload:載荷,也是一個JSON 對象,用來存放實際需要傳遞的資料。不建議存放敏感資訊,例如密碼。
{ "iss": "a.com", // 签发人 "exp": "1d", // expiration time 过期时间 "sub": "test", // 主题 "aud": "", // 受众 "nbf": "", // Not Before 生效时间 "iat": "", // Issued At 签发时间 "jti": "", // JWT ID 编号 // 可以定义私有字段 "name": "", "admin": "" }
Signature 簽名 是對前兩部分的簽名,防止資料被竄改。需要指定一個密鑰。這個密鑰只有伺服器才知道,不能外洩。使用 Header 裡面指定的簽名演算法,依照公式產生簽名。
算出簽名後,把 Header、Payload、Signature 三個部分拼成的一個字串,每個部分之間用 . 分隔。這樣就產生了一個token
二、何為雙token
#accessToken
:使用者取得資料權限
- #refreshToken
:用來取得新的accessToken
雙token 驗證機制,其中accessToken 過期時間較短,refreshToken 過期時間較長。當 accessToken 過期後,使用 refreshToken 去請求新的 token。
雙 token 驗證流程
- 使用者登入向服務端傳送帳號密碼,登入失敗傳回客戶端重新登入。登入成功服務端產生 accessToken 和 refreshToken,傳回產生的 token 給客戶端。
- 在請求攔截器中,請求頭中攜帶 accessToken 請求數據,服務端驗證 accessToken 是否過期。 token 有效繼續請求數據,token 失效返回失效訊息到客戶端。
- 客戶端收到服務端發送的請求訊息,在二次封裝的 axios 的回應攔截器中判斷是否有 accessToken 失效的訊息,沒有回傳回應的資料。有失效的訊息,就攜帶 refreshToken 請求新的 accessToken。
服務端驗證 refreshToken 是否有效。有效,重新產生 token, 傳回新的 token 和提示訊息到客戶端,無效,傳回無效訊息給客戶端。
客戶端回應攔截器判斷回應訊息是否有 refreshToken 有效無效。無效,登出目前登入。有效,重新儲存新的 token,繼續請求上一次要求的資料。
注意事項
短token失效,服務端拒絕請求,返回token失效訊息,前端請求到新的短token如何再次請求數據,達到無感刷新的效果。
服務端白名單,成功登入前是還沒有請求到token的,那麼如果服務端攔截請求,就無法登入。客製化白名單,讓登入無需進行token驗證。
三、服務端程式碼
#1. 建立koa2伺服器
全域安裝koa腳手架
npm install koa-generator -g
建立服務端直接koa2專案名稱
koa2 server
cd server 進入到專案安裝jwt
npm i jsonwebtoken
為了方便直接在服務端使用koa-cors 跨網域
npm i koa-cors
const cors=require('koa-cors')
...
app.use(cors())
登入後複製
2. 雙token新utils/token.jsconst cors=require('koa-cors') ... app.use(cors())
const jwt=require('jsonwebtoken') const secret='2023F_Ycb/wp_sd' // 密钥 /* expiresIn:5 过期时间,时间单位是秒 也可以这么写 expiresIn:1d 代表一天 1h 代表一小时 */ // 本次是为了测试,所以设置时间 短token5秒 长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 }
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
}
})
/*用于测试的获取数据接口*/
router.get('/getTestData',(ctx)=>{
let code,msg,data=null
code=2000
msg='获取数据成功'
ctx.body={
code,
msg,
data
}
})
/*验证长token是否有效,刷新短token
这里要注意,在刷新短token的时候回也返回新的长token,延续长token,
这样活跃用户在持续操作过程中不会被迫退出登录。长时间无操作的非活
跃用户长token过期重新登录
*/
router.get('/refresh',(ctx)=>{
let code,msg,data=null
//获取请求头中携带的长token
let r_tk=ctx.request.headers['pass']
//解析token 参数 token 密钥 回调函数返回信息
jwt.verify(r_tk,secret,(error)=>{
if(error){
code=4006,
msg='长token无效,请重新登录'
} else{
code=2000,
msg='长token有效,返回新的token',
data={
accessToken:getAccessToken(),
refreshToken:getReferToken()
}
}
})
})
登入後複製
4. 應用中間件utils/auth.jsconst 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 } }) /*用于测试的获取数据接口*/ router.get('/getTestData',(ctx)=>{ let code,msg,data=null code=2000 msg='获取数据成功' ctx.body={ code, msg, data } }) /*验证长token是否有效,刷新短token 这里要注意,在刷新短token的时候回也返回新的长token,延续长token, 这样活跃用户在持续操作过程中不会被迫退出登录。长时间无操作的非活 跃用户长token过期重新登录 */ router.get('/refresh',(ctx)=>{ let code,msg,data=null //获取请求头中携带的长token let r_tk=ctx.request.headers['pass'] //解析token 参数 token 密钥 回调函数返回信息 jwt.verify(r_tk,secret,(error)=>{ if(error){ code=4006, msg='长token无效,请重新登录' } else{ code=2000, msg='长token有效,返回新的token', data={ accessToken:getAccessToken(), refreshToken:getReferToken() } } }) })
const { secret } = require('./token')
const jwt = require('jsonwebtoken')
/*白名单,登录、刷新短token不受限制,也就不用token验证*/
const whiteList=['/login','/refresh']
const isWhiteList=(url,whiteList)=>{
return whiteList.find(item => item === url) ? true : false
}
/*中间件
验证短token是否有效
*/
const cuth = async (ctx,next)=>{
let code, msg, data = null
let url = ctx.path
if(isWhiteList(url,whiteList)){
// 执行下一步
return await next()
} else {
// 获取请求头携带的短token
const a_tk=ctx.request.headers['authorization']
if(!a_tk){
code=4003
msg='accessToken无效,无权限'
ctx.body={
code,
msg,
data
}
} else{
// 解析token
await jwt.verify(a_tk,secret.(error)=>{
if(error)=>{
code=4003
msg='accessToken无效,无权限'
ctx.body={
code,
msg,
datta
}
} else {
// token有效
return await next()
}
})
}
}
}
module.exports=auth
登入後複製
在app.js中引入應用中間件const { secret } = require('./token') const jwt = require('jsonwebtoken') /*白名单,登录、刷新短token不受限制,也就不用token验证*/ const whiteList=['/login','/refresh'] const isWhiteList=(url,whiteList)=>{ return whiteList.find(item => item === url) ? true : false } /*中间件 验证短token是否有效 */ const cuth = async (ctx,next)=>{ let code, msg, data = null let url = ctx.path if(isWhiteList(url,whiteList)){ // 执行下一步 return await next() } else { // 获取请求头携带的短token const a_tk=ctx.request.headers['authorization'] if(!a_tk){ code=4003 msg='accessToken无效,无权限' ctx.body={ code, msg, data } } else{ // 解析token await jwt.verify(a_tk,secret.(error)=>{ if(error)=>{ code=4003 msg='accessToken无效,无权限' ctx.body={ code, msg, datta } } else { // token有效 return await next() } }) } } } module.exports=auth
const auth=requier(./utils/auth) ··· app.use(auth)
四、前端程式碼
1. Vue3 Vite框架
#前端使用了Vue3 Vite的框架,看個人使用習慣。
npm init vite@latest client_side
安裝axios
npm i axios
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头部 携带长token

export {REFRESH_TOKEN,PASS} from '../config/constants.js' import { getRefreshToken, removeRefreshToken, setAccessToken, setRefreshToken} from '../config/storage' let subsequent=[] let flag=false // 设置开关,保证一次只能请求一次短token,防止客户多此操作,多次请求 /*把过期请求添加在数组中*/ export const addRequest = (request) => { subscribes.push(request) } /*调用过期请求*/ export const retryRequest = () => { console.log('重新请求上次中断的数据'); subscribes.forEach(request => request()) subscribes = [] } /*短token过期,携带token去重新请求token*/ export const refreshToken=()=>{ if(!flag){ flag = true; let r_tk = getRefershToken() // 获取长token if(r_tk){ server.get('/refresh',Object.assign({},{ headers:{[PASS]=r_tk} })).then((res)=>{ //长token失效,退出登录 if(res.code===4006){ flag = false removeRefershToken(REFRESH_TOKEN) } else if(res.code===2000){ // 存储新的token setAccessToken(res.data.accessToken) setRefreshToken(res.data.refreshToken) flag = false // 重新请求数据 retryRequest() } }) } } }
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', // 你的服务器 timeout: 1000 * 10, headers: { "Content-type": "application/json" } }) /*请求拦截器*/ server.interceptors.request.use(config => { // 获取短token,携带到请求头,服务端校验 let aToken = storage.getAccessToken(constants.ACCESS_TOKEN) config.headers[constants.AUTH] = aToken return config }) /*响应拦截器*/ server.interceptors.response.use( async response => { // 获取到配置和后端响应的数据 let { config, data } = response console.log('响应提示信息:', data.msg); return new Promise((resolve, reject) => { // 短token失效 if (data.code === 4003) { // 移除失效的短token storage.removeAccessToken(constants.ACCESS_TOKEN) // 把过期请求存储起来,用于请求到新的短token,再次请求,达到无感刷新 addRequest(() => resolve(server(config))) // 携带长token去请求新的token refreshToken() } else { // 有效返回相应的数据 resolve(data) } }) }, error => { return Promise.reject(error) } )
import * as constants from "./constants" // 存储短token export const setAccessToken = (token) => localStorage.setItem(constanst.ACCESS_TOKEN, token) // 存储长token export const setRefershToken = (token) => localStorage.setItem(constants.REFRESH_TOKEN, token) // 获取短token export const getAccessToken = () => localStorage.getItem(constants.ACCESS_TOKEN) // 获取长token export const getRefershToken = () => localStorage.getItem(constants.REFRESH_TOKEN) // 删除短token export const removeAccessToken = () => localStorage.removeItem(constants.ACCESS_TOKEN) // 删除长token export const removeRefershToken = () => localStorage.removeItem(constants.REFRESH_TOKEN)
import server from "../utils/server"; /*登录*/ export const login = () => { return server({ url: '/login', method: 'get' }) } /*请求数据*/ export const getData = () => { return server({ url: '/getList', method: 'get' }) }
以上是Vue3+Vite怎麼使用雙token實現無感刷新的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

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

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

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

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

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

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

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

Vue3+TS+Vite開發技巧:如何進行SEO優化SEO(SearchEngineOptimization)是指透過優化網站的結構、內容和關鍵字等方面,使其在搜尋引擎的排名更靠前,從而增加網站的流量和曝光度。在Vue3+TS+Vite等現代前端技術的開發中,如何進行SEO最佳化是一個很重要的問題。本文將介紹一些Vue3+TS+Vite開發的技巧與方法,幫

vue3+vite:src使用require動態導入圖片報錯和解決方法vue3+vite動態的導入多張圖片vue3如果使用的是typescript開發,就會出現require引入圖片報錯,requireisnotdefined不能像使用vue2這樣imgUrl:require(' …/assets/test.png')導入,是因為typescript不支援require所以用import導入,下面介紹如何解決:使用awaitimport

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

Vue3+TS+Vite開發技巧:如何進行前端安全防護隨著前端技術的不斷發展,越來越多的企業和個人開始使用Vue3+TS+Vite進行前端開發。然而,隨之而來的安全風險也引起了人們的注意。在本文中,我們將探討一些常見的前端安全性問題,並分享一些在Vue3+TS+Vite開發過程中如何進行前端安全防護的技巧。輸入驗證使用者的輸入往往是前端安全漏洞的主要來源之一。在

登入token無效的解決辦法有檢查Token是否過期、檢查Token是否正確、檢查Token是否被篡改、檢查Token是否與使用者匹配、清除快取或Cookie、檢查網路連線和伺服器狀態、重新登入或請求新的Token、聯絡技術支援或開發人員等。詳細介紹:1、檢查Token是否過期,登入Token通常會設定有效期,一旦超過有效期,就會被認為無效等等。

Vue3+TS+Vite開發技巧:如何進行跨域請求和網路請求最佳化引言:在前端開發中,網路請求是非常常見的操作。如何優化網頁請求以提高頁面載入速度和使用者體驗是我們開發者需要思考的問題之一。同時,對於一些需要向不同網域發送請求的場景,我們需要解決跨域問題。本文將介紹如何在Vue3+TS+Vite開發環境下進行跨域請求以及網路請求的最佳化技巧。一、跨域請求解決方案使

登入token無效問題可以透過檢查網路連線、檢查token有效期、清除快取和Cookie、檢查登入狀態、聯絡應用程式開發者和加強帳號安全來解決。詳細介紹:1、檢查網路連接,重新連接網路或更換網路環境;2、檢查token有效期,重新取得一個新的token,或聯絡應用程式的開發者;3、清除快取和Cookie,清除瀏覽器快取和Cookie,然後重新登入應用程式;4、檢查登入狀態。

Vue3+TS+Vite開發技巧:如何進行資料加密和儲存隨著網路技術的快速發展,資料的安全性和隱私保護變得越來越重要。在Vue3+TS+Vite開發環境下,如何進行資料加密和存儲,是每個開發人員都需要面對的問題。本文將介紹一些常用的資料加密和儲存的技巧,幫助開發人員提升應用程式的安全性和使用者體驗。一、資料加密前端資料加密前端加密是保護資料安全性的重要一環。常用
