最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

雙token無感刷新機制的實現(xiàn)方法示例

 更新時間:2026年04月03日 09:59:42   作者:星眠  
無感刷新Token,是指在用戶正常操作期間,系統(tǒng)在后臺自動刷新Token的有效期,避免因Token過期而導(dǎo)致用戶被迫重新登錄,這篇文章主要介紹了雙token無感刷新機制實現(xiàn)的相關(guān)資料,需要的朋友可以參考下

前文我們實現(xiàn)了登錄鑒權(quán),接下來我們對其進行優(yōu)化,實現(xiàn)雙token無感刷新

什么是無感刷新?

舉個例子:

  1. 早上入園(登錄成功)

    • 前臺給你:當天門票(access_token)+ 年卡(refresh_token
  2. 玩過山車(請求數(shù)據(jù))

  3. 下午門票過期access_token失效)

    • 檢票員攔住你:"票過期了!"(接口返回401錯誤)
  4. 自動續(xù)票(無感刷新)

    • 你默默掏出年卡(refresh_token

    • 續(xù)票亭給你:新的當天門票(新access_token

  5. 繼續(xù)游玩(請求重發(fā))

    • 用新門票重新玩過山車(自動重試之前失敗的請求)

    • 你完全沒中斷游玩(用戶無感知)

簡單來說,就是將之前登錄鑒權(quán)使用的一個token換成兩個token,access_token(短token)和refresh_token(長token),access_token主要用于驗證用戶是否登錄,而refresh_token主要作用是更新access_token和refresh_token,從而延長用戶的使用時間,不需頻繁登錄。

如何實現(xiàn)雙token無感刷新?

1.將后端返回給登錄請求的數(shù)據(jù)中的單token改為access_token和refresh_token

router.prefix('/user')//路由前綴,表示所有路由都以/user開頭
router.post('/login',async (ctx)=>{
    const {username,password} = ctx.request.body
    try{
        const res = await userLogin(username,password)
        if(res.length){
            let data={
                id:res[0].id,
                username:res[0].username,
                nikeName:res[0].nikeName,
                create_time:res[0].create_time,
            }
            const access_token = sign(data,'1h')//生成短token令牌
            const refresh_token=sign(data,'7d')//生成長token令牌
            ctx.body={
                code:'1',//邏輯成功
                msg:'登錄成功',
                data,
                access_token:access_token,//登錄成功后,后端返回一個短token給前端   
                refresh_token:refresh_token//登錄成功后,后端返回一個長token給前端 
            }
        }else{
            ctx.body={
                code:'0',
                msg:'賬號或密碼錯誤',
            }
        }
    }catch(error){
        ctx.body={
            code:'-1',
            msg:'服務(wù)器異常',
            data:error
        }
    }
})

2.將access_token和refresh_token一起進行瀏覽器本地保存

用戶登錄成功后,才能接收到,并進行保存

  const onFinish = values => {
      axios.post('/user/login',values).then(res=>{
        toast.success('登錄成功')
        navigate('/noteClass')
        localStorage.setItem('access_token',res.access_token)//登錄成功后,將令牌(token)存儲到瀏覽器本地
        localStorage.setItem('refresh_token',res.refresh_token)//登錄成功后,將令牌(token)存儲到瀏覽器本地
      }).catch(err=>{
        console.log(err)
      })
  }

3. axios請求攔截器添加到請求頭上的數(shù)據(jù)改access_token

axios.interceptors.request.use(request => {
    const access_token = localStorage.getItem('access_token')//從瀏覽器本地獲取token
    if (access_token) {//如果令牌(token)存在,將令牌(token)放到請求頭中
        request.headers.Authorization = access_token//將令牌(token)放到請求頭中
    }
    return request//返回請求數(shù)據(jù)(放行)
})

4. 處理access_token過期邏輯

當首頁發(fā)送text接口請求時,后端驗證發(fā)現(xiàn)access_token過期了,則返回401狀態(tài)碼,axios響應(yīng)攔截器攔截到401狀態(tài)碼,則將瀏覽器中的refresh_token放入請求體,并發(fā)送refresh接口請求,后端收到refresh_token后對其進行驗證,如果refresh_token過期,直接返回416狀態(tài)碼,告訴前端跳轉(zhuǎn)登錄頁面,如果refresh_token驗證通過,則生成新的access_token和refresh_token,返回給前端,前端接收后,攜帶新的access_token重新發(fā)送text接口請求。

  1. 后端驗證access_token過期,返回401狀態(tài)碼
function verify(){
    //ctx最終為index.js中的use方法中的ctx參數(shù)
    //next為內(nèi)置的,表示執(zhí)行了app.use中的回調(diào)函數(shù)之后要運行一個next,這樣后面的app.use()才會生效
    return async (ctx,next)=>{
        //1.獲取請求頭中的token
        const token = ctx.request.headers.authorization
        //2.驗證token是否存在
        if(token){
            //3.驗證token是否正確
            try{
                const decoded = jwt.verify(token,'666')//解密token
                //判斷decoded是否存在,因為能解密成功,說明token沒有過期,且有id屬性
                if(decoded.id){
                    await next()//放行
                }
            }catch(error){//如果短token過期
                ctx.status=401
                ctx.body={
                    code:'0',
                    msg:'登錄過期,請重新登錄',
                }
            }
        }else{//無token
            ctx.status=402
            ctx.body={
                code:'0',
                msg:'請先登錄'
            }
        }
    }
}
  1. axios響應(yīng)攔截器攔截401,并進行access_token和refresh_token刷新
  • 將refresh_token作為請求體,發(fā)送refresh接口請求
(res) => {
        //后端返回的短token過期的狀態(tài)碼為401
        if (res.status === 401) {
            const originalRequest = res.config//獲取原始請求,將沒有成功的原始請求記錄下來
            //重新請求新的短token和長token
            const refresh_token = localStorage.getItem('refresh_token')//從瀏覽器本地獲取token
                if(refresh_token){
                    axios.post('/user/refresh',{refresh_token}).then(res=>{
                        if(res.code==='1'){
                            //將新的短token放到瀏覽器本地
                            localStorage.setItem('access_token',res.access_token)
                            //將新的長token放到瀏覽器本地
                            localStorage.setItem('refresh_token',res.refresh_token)
                            //將原始請求的headers中的Authorization屬性設(shè)置為新的短token
                            originalRequest.headers.Authorization = res.access_token
                            //重新發(fā)送原始請求
                            return axios(originalRequest)
                        }
                    })
                }
        }
        //如果長短token都過期了,后端返回的狀態(tài)碼為416
        if(res.status===416){
            toast.error(res.response.data.msg)
            setTimeout(() => {
                window.location.href = '/login'//使用原生js跳轉(zhuǎn)方式,跳轉(zhuǎn)到登錄頁
            }, 2000)
        }
        if(res.status===402){
            toast.error(res.response.data.msg)
            setTimeout(() => {
                window.location.href = '/login'//使用原生js跳轉(zhuǎn)方式,跳轉(zhuǎn)到登錄頁
            }, 2000)
    }
  • 驗證refresh_token是否過期
//驗證refresh_token
function refreshVerify(token){
    try{
        const decoded = jwt.verify(token,'666')//解密token
        if(decoded.id){
            return decoded
        }
    }catch(error){
        return false
    }
}
  • 驗證成功,刷新access_token和refresh_token
  • 失敗則返回416狀態(tài)碼
router.post('/refresh',async (ctx)=>{
    const {refresh_token} =ctx.request.body
    //校驗refresh_token是否有效
    const vaild=refreshVerify(refresh_token)
    if(vaild.id){//如果長token解密成功
        //創(chuàng)建新的長短token
        const data={
            id:vaild.id,
            username:vaild.username,
            nikeName:vaild.nikeName,
            create_time:vaild.create_time,
        }
        const access_token = sign(data,'1h')//生成短token令牌
        const refresh_token=sign(data,'7d')//生成長token令牌
        ctx.body={
            code:'1',
            msg:'刷新成功',
            access_token:access_token,
            refresh_token:refresh_token,
        }
    }else{//長token過期
        ctx.status=416,
        ctx.body={
            code:'0',
            msg:'登錄過期,請重新登錄',
        }
    }
})
  • 最后重新發(fā)送text接口請求(代碼在第一小點后面)

總結(jié) 

到此這篇關(guān)于雙token無感刷新機制實現(xiàn)的文章就介紹到這了,更多相關(guān)雙token無感刷新機制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論

刚察县| 垦利县| 绥江县| 香港| 定边县| 五大连池市| 佳木斯市| 铁岭县| 惠州市| 襄汾县| 乳山市| 七台河市| 新蔡县| 南充市| 香河县| 澄江县| 商都县| 中山市| 资阳市| 扶余县| 聂拉木县| 开鲁县| 扎兰屯市| 洛宁县| 弋阳县| 辽中县| 柘城县| 怀化市| 湖北省| 额尔古纳市| 铁岭县| 平乡县| 台州市| 苍溪县| 邢台县| 松溪县| 渭南市| 梨树县| 许昌市| 德庆县| 乃东县|