首页IT科技前端无感刷新token(记录–关于无感刷新Token,我是这样子做的)

前端无感刷新token(记录–关于无感刷新Token,我是这样子做的)

时间2025-05-05 23:04:50分类IT科技浏览4764
导读:这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 标头 header...

这里给大家分享我在网上总结出来的一些知识            ,希望对大家有所帮助

标头 header

标头是一个JSON对象                  ,由两个部分组成      ,分别是令牌是类型(JWT)和签名算法(SHA256         ,RSA)

{ "alg": "HS256", "typ": "JWT" }
负荷 payload

负荷部分也是一个JSON对象                  ,用于存放需要传递的数据         ,例如用户的信息

{ "username": "_island", "age": 18 }

此外      ,JWT规定了7个可选官方字段(建议)

属性 说明 iss JWT签发人 exp JWT过期时间 sub JWT面向用户 aud JWT接收方 nbf JWT生效时间 iat JWT签发时间 jti JWT编号

签章 signature

这一部分                  ,是由前面两个部分的签名            ,防止数据被篡改            。 在服务器中指定一个密钥   ,使用标头中指定的签名算法                  ,按照下面的公式生成这签名数据

HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

在拿到签名数据之后               ,把这三个部分的数据拼接起来,每个部分中间使用.来分隔                  。这样子我们就生成出一个了JWT数据了               ,接下来返回给客户端储存起来      。而且客户端在发起请求时                  ,携带这个JWT在请求头中的Authorization字段   ,服务器通过解密的方式即可识别出对应的用户信息         。

JWT优势和弊端

优势 数据体积小            ,传输速度快 无需额外资源开销来存放数据 支持跨域验证使用 弊端 生成出来的Token无法撤销                  ,即使重置账号密码之前的Token也是可以使用的(需等待JWT过期) 无法确认用户已经签发了多少个JWT 不支持refreshToken

关于refreshToken

refreshToken是Oauth2认证中的一个概念      ,和accessToken一起生成出来的                  。

当用户携带的这个accessToken过期时         ,用户就需要在重新获取新的accessToken                  ,而refreshToken就用来重新获取新的accessToken的凭证         。

为什么要有refreshToken

当你第一次接触的时候         ,你有没有一个这样子的疑惑      ,为什么需要refreshToken这个东西                  ,而不是服务器端给一个期限较长甚至永久性的accessToken呢?

抱着这个疑惑我在网上搜寻了一番            ,

其实这个accessToken的使用期限有点像我们生活中的入住酒店   ,当我们在入住酒店时                  ,会出示我们的身份证明来登记获取房卡               ,此时房卡相当于accessToken,可以访问对应的房间               ,当你的房卡过期之后就无法再开启房门了                  ,此时就需要再到前台更新一下房卡   ,才能正常进入            ,这个过程也就相当于refreshToken      。

accessToken使用率相比refreshToken频繁很多                  ,如果按上面所说如果accessToken给定一个较长的有效时间      ,就会出现不可控的权限泄露风险                  。

使用refreshToken可以提高安全性

用户在访问网站时         ,accessToken被盗取了                  ,此时攻击者就可以拿这个accessToke访问权限以内的功能了            。如果accessToken设置一个短暂的有效期2小时         ,攻击者能使用被盗取的accessToken的时间最多也就2个小时      ,除非再通过refreshToken刷新accessToken才能正常访问   。

设置accessToken有效期是永久的                  ,用户在更改密码之后            ,之前的accessToken也是有效的

总体来说有了refreshToken可以降低accessToken被盗的风险

关于JWT无感刷新TOKEN方案(结合axios)

业务需求

在用户登录应用后   ,服务器会返回一组数据                  ,其中就包含了accessToken和refreshToken               ,每个accessToken都有一个固定的有效期,如果携带一个过期的token向服务器请求时               ,服务器会返回401的状态码来告诉用户此token过期了                  ,此时就需要用到登录时返回的refreshToken调用刷新Token的接口(Refresh)来更新下新的token再发送请求即可                  。

话不多说   ,先上代码

工具

axios作为最热门的http请求库之一            ,我们本篇文章就借助它的错误响应拦截器来实现token无感刷新功能               。

具体实现

本次基于axios-bz代码片段封装响应拦截器 可直接配置到你的项目中使用 ✈️ ✈️

利用interceptors.response                  ,在业务代码获取到接口数据之前进行状态码401判断当前携带的accessToken是否失效。 下面是关于interceptors.response中异常阶段处理内容               。当响应码为401时      ,响应拦截器会走中第二个回调函数onRejected

下面代码分段可能会让大家阅读起来不是很顺畅         ,我直接把整份代码贴在下面                  ,且每一段代码之间都添加了对应的注释

// 最大重发次数 const MAX_ERROR_COUNT = 5; // 当前重发次数 let currentCount = 0; // 缓存请求队列 const queue: ((t: string) => any)[] = []; // 当前是否刷新状态 let isRefresh = false; export default async (error: AxiosError<ResponseDataType>) => { const statusCode = error.response?.status; const clearAuth = () => { console.log(身份过期         ,请重新登录); window.location.replace(/login); // 清空数据 sessionStorage.clear(); return Promise.reject(error); }; // 为了节省多余的代码      ,这里仅展示处理状态码为401的情况 if (statusCode === 401) { // accessToken失效 // 判断本地是否有缓存有refreshToken const refreshToken = sessionStorage.get(refresh) ?? null; if (!refreshToken) { clearAuth(); } // 提取请求的配置 const { config } = error; // 判断是否refresh失败且状态码401                  ,再次进入错误拦截器 if (config.url?.includes(refresh)) { clearAuth(); } // 判断当前是否为刷新状态中(防止多个请求导致多次调refresh接口) if (!isRefresh) { // 设置当前状态为刷新中 isRefresh = true; // 如果重发次数超过            ,直接退出登录 if (currentCount > MAX_ERROR_COUNT) { clearAuth(); } // 增加重试次数 currentCount += 1; try { const { data: { access }, } = await UserAuthApi.refreshToken(refreshToken); // 请求成功   ,缓存新的accessToken sessionStorage.set(token, access); // 重置重发次数 currentCount = 0; // 遍历队列                  ,重新发起请求 queue.forEach((cb) => cb(access)); // 返回请求数据 return ApiInstance.request(error.config); } catch { // 刷新token失败               ,直接退出登录 console.log(请重新登录); sessionStorage.clear(); window.location.replace(/login); return Promise.reject(error); } finally { // 重置状态 isRefresh = false; } } else { // 当前正在尝试刷新token,先返回一个promise阻塞请求并推进请求列表中 return new Promise((resolve) => { // 缓存网络请求               ,等token刷新后直接执行 queue.push((newToken: string) => { Reflect.set(config.headers!, authorization, newToken); // @ts-ignore resolve(ApiInstance.request<ResponseDataType<any>>(config)); }); }); } } return Promise.reject(error); };

抽离代码

把上面关于调用刷新token的代码抽离成一个refreshToken函数                  ,单独处理这一情况   ,这样子做有利于提高代码的可读性和维护性            ,且让看上去代码不是很臃肿

// refreshToken.ts export default async function refreshToken(error: AxiosError<ResponseDataType>) { /* 将上面 if (statusCode === 401) 中的代码贴进来即可                  ,这里就不重复啦 代码仓库地址: https://github.com/QC2168/axios-bz/blob/main/Interceptors/hooks/refreshToken.ts */ }

经过上面的逻辑抽离      ,现在看下拦截器中的代码就很简洁了         ,后续如果要调整相关逻辑直接在refreshToken.ts文件中调整即可                  。

import refreshToken from ./refreshToken.ts export default async (error: AxiosError<ResponseDataType>) => { const statusCode = error.response?.status; // 为了节省多余的代码                  ,这里仅展示处理状态码为401的情况 if (statusCode === 401) { refreshToken() } return Promise.reject(error); };

本文转载于:

https://juejin.cn/post/7170278285274775560

如果对您有所帮助         ,欢迎您点个关注      ,我会定时更新技术文档                  ,大家一起讨论学习            ,一起进步   。

声明:本站所有文章   ,如无特殊说明或标注                  ,均为本站原创发布            。任何个人或组织               ,在未征得本站同意时,禁止复制            、盗用                  、采集      、发布本站内容到任何网站         、书籍等各类媒体平台                  。如若本站内容侵犯了原著者的合法权益               ,可联系我们进行处理      。

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
购物车的东西如何删除(WooCommerce购物车按钮删除和隐藏几种方法(购物车里怎删掉))