vue中雙token和無感刷新token的區(qū)別
為什么有這篇小作文?
最近要給自己的項(xiàng)目加上token自動(dòng)續(xù)期,但是在網(wǎng)上搜的寫法五花八門,有的光前端部分就寫了幾百行代碼,我看著費(fèi)勁,摸了半天也沒有實(shí)現(xiàn),所以決定自己造輪子
項(xiàng)目構(gòu)成
- 后端部分:使用golang的gin框架起的服務(wù)
- 前端部分:vue+elementui
先說后端部分,后端邏輯相對(duì)前端簡單點(diǎn),關(guān)鍵三步
登陸接口生成雙token
"github.com/dgrijalva/jwt-go"
func (this UserController) DoLogin(ctx *gin.Context) {
username := ctx.Request.FormValue("username")
passWord := ctx.Request.FormValue("password")
passMd5 := middlewares.CreateMD5(passWord)
expireTime := time.Now().Add(10 * time.Second).Unix() //token過期時(shí)間10秒,主要是測試方便
refreshTime := time.Now().Add(20 * time.Second).Unix() //刷新的時(shí)間限制,超過20秒重新登錄
user := []modules.User{}
err := modules.DB.Model(&modules.User{}).Where("username = ? AND password = ?", username, passMd5).Find(&user).Error
if err != nil || len(user) == 0 {
ctx.JSON(400, gin.H{
"success": false,
"message": "用戶名或密碼錯(cuò)誤",
})
} else {
println("expireTime", string(rune(expireTime)))
myClaims := MyClaims{
user.Id,
jwt.StandardClaims{
ExpiresAt: expireTime,
},
}
myClaimsRefrrsh := MyClaims{
user.Id,
jwt.StandardClaims{
ExpiresAt: refreshTime,
},
}
jwtKey := []byte("lyf123456")
tokenObj := jwt.NewWithClaims(jwt.SigningMethodHS256, myClaims)
tokenStr, err := tokenObj.SignedString(jwtKey)
tokenFresh := jwt.NewWithClaims(jwt.SigningMethodHS256, myClaimsRefrrsh)
tokenStrRefresh, err2 := tokenFresh.SignedString(jwtKey)
if err != nil && err2 != nil {
ctx.JSON(200, gin.H{
"message": "生成token失敗",
"success": false,
})
} else {
ctx.JSON(200, gin.H{
"message": "登錄成功",
"success": true,
"token": tokenStr,//數(shù)據(jù)請(qǐng)求的token
"refreshToken": tokenStrRefresh,//刷新token用的
})
}
}
}刷新token的方法
func (this UserController) RefrshToken(ctx *gin.Context) {
tokenData := ctx.Request.Header.Get("Authorization") //這里是個(gè)關(guān)鍵點(diǎn),刷新token時(shí)也要帶上token,不過這里是前端傳的refreshToken
if tokenData == "" {
ctx.JSON(401, gin.H{
"message": "token為空",
"success": false,
})
ctx.Abort()
return
}
tokenStr := strings.Split(tokenData, " ")[1]
_, claims, err := middlewares.ParseToken(tokenStr)
expireTime := time.Now().Add(10 * time.Second).Unix()
refreshTime := time.Now().Add(20 * time.Second).Unix()
if err != nil {
ctx.JSON(400, gin.H{
"success": false,
"message": "token傳入錯(cuò)誤",
})
} else {
myClaims := MyClaims{
claims.Uid,
jwt.StandardClaims{
ExpiresAt: expireTime,
},
}
myClaimsRefrrsh := MyClaims{
claims.Uid,
jwt.StandardClaims{
ExpiresAt: refreshTime,
},
}
jwtKey := []byte("lyf123456")
tokenObj := jwt.NewWithClaims(jwt.SigningMethodHS256, myClaims)
tokenStr, err := tokenObj.SignedString(jwtKey)
tokenFresh := jwt.NewWithClaims(jwt.SigningMethodHS256, myClaimsRefrrsh)
tokenStrRefresh, err2 := tokenFresh.SignedString(jwtKey)
if err != nil && err2 != nil {
ctx.JSON(400, gin.H{
"message": "生成token失敗",
"success": false,
})
} else {
ctx.JSON(200, gin.H{
"message": "刷新token成功",
"success": true,
"token": tokenStr,
"refreshToken": tokenStrRefresh,
})
}
}
}路由中間件里驗(yàn)證token
package middlewares
import (
"strings"
"github.com/dgrijalva/jwt-go"
"github.com/gin-gonic/gin"
)
type MyClaims struct {
Uid int
jwt.StandardClaims
}
func AuthMiddleWare(c *gin.Context) {
tokenData := c.Request.Header.Get("Authorization")
if tokenData == "" {
c.JSON(401, gin.H{
"message": "token為空",
"success": false,
})
c.Abort()
return
}
tokenStr := strings.Split(tokenData, " ")[1]
token, _, err := ParseToken(tokenStr)
if err != nil || !token.Valid {
// 這里我感覺覺是個(gè)關(guān)鍵點(diǎn),我看別人寫的,過期了返回401,但是前端的axios的響應(yīng)攔截器里捕獲不到,所以我用201狀態(tài)碼,
c.JSON(201, gin.H{
"message": "token已過期",
"success": false,
})
c.Abort()
return
} else {
c.Next()
}
}
func ParseToken(tokenStr string) (*jwt.Token, *MyClaims, error) {
jwtKey := []byte("lyf123456")
// 解析token
myClaims := &MyClaims{}
token, err := jwt.ParseWithClaims(tokenStr, myClaims, func(token *jwt.Token) (interface{}, error) {
return jwtKey, nil
})
return token, myClaims, err
}總結(jié)一下:后端部分三步,1.登陸時(shí)生成雙token,2,路由中間件里驗(yàn)證token,過期時(shí)返回201狀態(tài)碼(201是我私人定的,并不是行業(yè)標(biāo)準(zhǔn))。3,刷新token的方法里也和登陸接口一樣返回雙token
前端部分
前端部分在axios封裝時(shí)候加攔截器判斷token是否過期,我這里跟別人寫的最大的不同點(diǎn)是:我創(chuàng)建了兩個(gè)axios對(duì)象,一個(gè)正常數(shù)據(jù)請(qǐng)求用(server),另一個(gè)專門刷新token用(serverRefreshToken),這樣寫的好處是省去了易錯(cuò)的判斷邏輯
import axios from 'axios'
import { ElMessage } from 'element-plus'
import router from '../router'
//數(shù)據(jù)請(qǐng)求用
const server=axios.create({
baseURL:'/shopApi',
timeout:5000
})
// 刷新token專用
const serverRefreshToken=axios.create({
baseURL:'/shopApi',
timeout:5000
})
//獲取新token的方法
async function getNewToken(){
let res=await serverRefreshToken.request({
url:`/admin/refresh`,
method:"post",
})
if(res.status==200){
sessionStorage.setItem("token",res.data.token)
sessionStorage.setItem("refreshToken",res.data.refreshToken)
return true
}else{
ElMessage.error(res.data.message)
router.push('/login')
return false
}
}
//這里是正常獲取數(shù)據(jù)用的請(qǐng)求攔截器,主要作用是給所有請(qǐng)求的請(qǐng)求頭里加上token
server.interceptors.request.use(config=>{
let token=""
token=sessionStorage.getItem("token")
if(token){
config.headers.Authorization="Bearer "+token
}
return config
},error=>{
Promise.reject(error)
})
//這里是正常獲取數(shù)據(jù)用的響應(yīng)攔截器,正常數(shù)據(jù)請(qǐng)求都是200狀態(tài)碼,當(dāng)攔截到201狀態(tài)碼時(shí),代表token過期了,
// 應(yīng)熱心小伙伴的提醒,加上防止token過期后正好短時(shí)間內(nèi)多個(gè)請(qǐng)求重復(fù)刷新token,刷新token成功再請(qǐng)求
let isRefreshing=false
let refreshFnArr=[]
server.interceptors.response.use(async(res)=>{
if(res.status==201){
if(!isRefreshing){
// 如果正好段時(shí)間內(nèi)觸發(fā)了多個(gè)請(qǐng)求
isRefreshing=true
let bl=await getNewToken()
if(bl){
refreshFnArr.forEach(fn=>{
fn()
})
refreshFnArr=[]
res= await server.request(res.config)
isRefreshing=false
}
}else{
return new Promise(resolve=>{
refreshFnArr.push(
()=>{
resolve(res.config)
}
)
})
}
}
return res
},error=>{
if(error.response.status==500||error.response.status==401||error.response.status==400){
router.push('/login')
ElMessage.error(error.response.data.message)
Promise.reject(error)
}
})
//這里是刷新token專用的axios對(duì)象,他的作用是給請(qǐng)求加上刷新token專用的refreshToken
serverRefreshToken.interceptors.request.use(config=>{
let token=""
token=sessionStorage.getItem("refreshToken")
if(token){
config.headers.Authorization="Bearer "+token
}
return config
},error=>{
Promise.reject(error)
})
export default server總結(jié)一下,前端部分:1,正常數(shù)據(jù)請(qǐng)求和刷新token用的請(qǐng)求分開了,各司其職。省去復(fù)雜的判斷。2,獲取新的token和refreshToken后更新原來舊的token和refreshToken。(完結(jié))
到此這篇關(guān)于vue中雙token和無感刷新token的區(qū)別的文章就介紹到這了,更多相關(guān)vue中雙token和無感刷新token內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 前端登錄token失效實(shí)現(xiàn)雙Token無感刷新詳細(xì)步驟
- SpringBoot中雙token實(shí)現(xiàn)無感刷新
- 雙Token實(shí)現(xiàn)無感刷新的完整代碼示例
- 雙token無感刷新nodejs+React詳細(xì)解釋(保姆級(jí)教程)
- node.js實(shí)現(xiàn)雙Token+Cookie存儲(chǔ)+無感刷新機(jī)制的示例
- 雙Token無感刷新機(jī)制實(shí)現(xiàn)方式
- 前端雙token無感刷新圖文詳解
- Vue實(shí)現(xiàn)雙token無感刷新的示例代碼
- Vue3+Vite使用雙token實(shí)現(xiàn)無感刷新
- SpringBoot+React中雙token實(shí)現(xiàn)無感刷新
相關(guān)文章
微信小程序scroll-view實(shí)現(xiàn)字幕滾動(dòng)
這篇文章主要為大家詳細(xì)介紹了微信小程序scroll-view實(shí)現(xiàn)字幕滾動(dòng)效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-07-07
JS?for?in遍歷對(duì)象順序不對(duì)解決辦法
最近使用for-in語句遍歷對(duì)象屬性時(shí)發(fā)現(xiàn)遍歷順序并非屬性構(gòu)建順序,這篇文章主要給大家介紹了關(guān)于JS?for?in遍歷對(duì)象順序不對(duì)的解決辦法,需要的朋友可以參考下2023-11-11
JavaScript實(shí)現(xiàn)節(jié)假日日歷應(yīng)用開發(fā)全過程
在Web開發(fā)中,日歷控件是一個(gè)常見的組件,用于顯示日期并幫助用戶選擇日期,這篇文章主要介紹了JavaScript實(shí)現(xiàn)節(jié)假日日歷應(yīng)用開發(fā)的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2025-10-10
javascript 簡單抽屜效果的實(shí)現(xiàn)代碼
javascript 簡單抽屜效果的實(shí)現(xiàn)代碼,需要的朋友可以參考下,大家自行測試。2010-03-03
JS實(shí)現(xiàn)圖片橫向滾動(dòng)效果示例代碼
圖片橫向滾動(dòng)效果,大家可能都已經(jīng)很熟悉了,本文為大家介紹下使用js實(shí)現(xiàn)橫向滾動(dòng)效果,喜歡的朋友可以參考下,希望對(duì)大家有所幫助2013-09-09
jszip插件實(shí)現(xiàn)圖片打包下載的方法分析
這篇文章主要介紹了jszip插件實(shí)現(xiàn)圖片打包下載的方法,結(jié)合實(shí)例形式分析了JavaScript使用jszip插件依據(jù)圖片列表打包下載zip壓縮文件的相關(guān)操作技巧,需要的朋友可以參考下2023-05-05

