当前位置:

首页 > 编程开发 > Vue3+Vite怎么使用双token实现无感刷新

Vue3+Vite怎么使用双token实现无感刷新

一、token登录鉴权jwt:JSONWebToken。是一种认证协议,一般用来校验请求的身份信息和身份权限。由三部分组成:Header、Hayload、Signatureheader:也就是头部信息,是描述这个token的基本信息,json格式{"alg":"HS256",//表示签名的算法,默认是HMACSHA256(写成HS256)"type":"JWT"//表示Token的类型,JWT令牌统一写为JWT}payload:载荷,也是一个JSON对象,用来存放实际需要传递的数据。不建议存放敏感信息,比

本文目录

    一、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实现无感刷新

    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发 Vue3 vite
    相关文章 更多
    pinia数据持久化的步骤详解与插件配置教程
    pinia数据持久化的步骤详解与插件配置教程

    详解Pinia数据持久化的实现步骤,包括手动订阅状态、封装通用插件及处理序列化例外,帮助开发者构建稳定的前端状态存储方案。

    Token与Tokenizer是什么?分词、BPE与上下文长度
    Token与Tokenizer是什么?分词、BPE与上下文长度

    深入解析大模型中的Token与Tokenizer工作机制,通过BPE分词示例说明文字如何转化为数字编号,澄清上下文长度与字数的区别,帮助用户准确评估模型处理长文本的实际能力。

    vue创建项目很慢怎么解决及常见原因排查教程
    vue创建项目很慢怎么解决及常见原因排查教程

    分析Vue项目创建缓慢的常见原因,包括网络延迟和依赖下载问题,提供切换镜像源、更换包管理器及使用Vite等具体优化方案,提升开发环境搭建效率。

    react怎么引入图片文件?本地图片导入方法详解
    react怎么引入图片文件?本地图片导入方法详解

    详解React项目中引入本地图片的正确姿势,对比import静态导入与require动态加载的差异,剖析打包工具处理资源的底层逻辑,解决路径报错与动态渲染失效问题。

    AI重构企业业务架构:超聚变“智企”范式核心解析
    AI重构企业业务架构:超聚变“智企”范式核心解析

    本文解析超聚变在2026数博会发布的“智企”范式,重点阐述如何通过Token生产平台(Token Factory)与企业业务本体建模,实现从简单AI工具调用到企业应用架构系统性重构的演进。文章详细拆解了智能体编排、数字孪生及生态协同等关键技术路径,为AI时代企业数字化转型提供可落地的参考方案。

    总价值上亿元!360全员每人发1亿Token:周鸿祎想通了一件事
    总价值上亿元!360全员每人发1亿Token:周鸿祎想通了一件事

    360公司向全体员工每人发放1亿Token,总价值近亿元,旨在鼓励员工深度使用AI工具以提升效率。此举绕过了传统审批流程,大幅降低使用门槛。公司同时推出“龙虾教练”功能,通过对话式引导帮助员工轻松训练专属AI助手,进一步推动AI技术的普及与应用。

    硅谷程序员开始卷Token消耗量 脸书母公司Meta把AI使用量写进KPI
    硅谷程序员开始卷Token消耗量 脸书母公司Meta把AI使用量写进KPI

    3月27日,据央视财经,在美国硅谷,最近出现了一种新的“攀比”,比的不是加班时间,而是你用了多少AI的“Token”,也就是词元。这种情况在程序员群体当中尤为显著,在一些公司,员工甚至会在内部排行榜上比拼谁消耗的“Token”更多。 想象一下,硅谷的竞争风向又转了。过去可能比谁下班更晚,现在呢?大家

    Token经济崛起:迅策(03317)有望跻身AI“千亿俱乐部”
    Token经济崛起:迅策(03317)有望跻身AI“千亿俱乐部”

    智通财经APP获悉,AI行业正式从“补贴烧钱”跨入“商业化定价时代”。被市场称为“Token第一股”的迅策(03317)迎来利好!叠加近日国泰君安国际已将目标价大幅上调至245港元/股。迅策有望成为AI“千亿俱乐部”的新成员。 中国AI弯道超车:价格优势构筑竞争力 风向正在转变。日前,人工智能公司A

    海光全球首发“机密Token”:把云端大模型装进“笼子”里
    海光全球首发“机密Token”:把云端大模型装进“笼子”里

    4月8日,海光信息全球首发“机密Token”技术,为云端大模型应用上锁 大模型好用,但数据隐私终究是个“心病”。把核心数据明文送上云端,总让人感觉像把钥匙交给了别人。这个痛点,现在有了新的解法。4月8日,海光信息(688041.SH)发布了一项名为“机密Token”的技术。简单来说,这项技术旨在让用

    如何从零开始搭建vue3项目
    如何从零开始搭建vue3项目

    说明记录一次Vue3的项目搭建过程。文章基于vue3.2.6和vite2.51版本,使用了ui库Elementplus,vue-router4,Layout布局封装,axios请求封装,别名配置等。开始1.使用vscode开发工具安装vue3的插件Volar,在vue2中我们使用的是Vetur。vue3在线code工具传送门sfc.vuejs.org/2.执行初始化及安装命令:npminitvite初始化vite此过程可以输入项目名、选择vue/react项目及js/ts环境选择,vue3已经完全支持ts

    查看更多
    精品专题 更多
    装机必备
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows
    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程
    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    Mac软件 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    Aperty macOS版
    Aperty macOS版
    macOS

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    WINDOWS 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    PixTV 网页版
    PixTV 网页版
    Windows

    PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。