日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

一、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

在app.js中引入應用cors

const cors=require('koa-cors')
...
app.use(cors())

2、雙token

新建utils/token.js

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
}

3、路由

直接使用腳手架創建的項目已經在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
    }
})
 
/*用于測試的獲取數據接口*/
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.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

在app.js中引入應用中間件

const auth=requier(./utils/auth)
···
app.use(auth)

其實如果只是做一個簡單的雙token驗證,很多中間件是沒必要的,比如解析靜態資源。不過為了節省時間,方便就直接使用了koa2腳手架。

最終目錄結構:


Vue3+Vite怎么使用雙token實現無感刷新


四、前端代碼

1、Vue3+Vite框架

前端使用了Vue3+Vite的框架,看個人使用習慣。

npm init vite@latest client_side

安裝axios

npm i axios
2、定義使用到的常量

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頭部 攜帶長token

3、存儲、調用過期請求

關鍵點:把攜帶過期token的請求,利用Promise存在數組中,保持pending狀態,也就是不調用resolve()。當獲取到新的token,再重新請求。 utils/refresh.js

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()
                }
            })
        }
    }
}
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', // 你的服務器
    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)
    }
)

5、復用封裝

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)

6、接口封裝

apis/index.js

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實現無感刷新


最后的最后,運行項目,查看效果 后端設置的短token5秒,長token10秒。登錄請求到token后,請求數據可以正常請求,五秒后再次請求,短token失效,這時長token有效,請求到新的token,refresh接口只調用了一次。長token也過期后,就需要重新登錄啦。


Vue3+Vite怎么使用雙token實現無感刷新

分享到:
標簽:Vue3+Vite token無感刷新
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定