为什么要有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失效// 判断本地是否有缓存有refreshTokenconst 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);// 请求成功,缓存新的accessTokensessionStorage.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-ignoreresolve(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);
};
为什么要有refreshToken相关推荐
- refreshtoken用mysql_「SpringCloud」 Spring Security OAuth2 Mysql管理在线Token
原标题:「SpringCloud」 Spring Security OAuth2 Mysql管理在线Token 前言:Spring Cloud 分布式中的登录如何可视化的管理目前下发的令牌.使用情况. ...
- Identityserver4中ResourceOwnerPassword 模式获取refreshtoken
一.IS4服务端配置 1.配置Client new Client{ClientId = "xamarin",ClientSecrets = { new Secret("s ...
- Asp Net Core 5 REST API 使用 RefreshToken 刷新 JWT - Step by Step(三)
翻译自 Mohamad Lawand 2021年1月25日的文章 <Refresh JWT with Refresh Tokens in Asp Net Core 5 Rest API Step ...
- SpringSecurity OAuth2 (7) 自定义 AccessToken 和 RefreshToken (JWT with RSA 签名)
文章目录 AuthorizationServer 引言 AuthorizationServerTokenServices ResourceServerTokenServices TokenStore ...
- accessToken refreshToken简单使用源码demo,双token刷新及有效时间设置
最后会附上源码 这篇介绍了一个项目中使用的双token登录认证刷新的demo,如需移植到生产项目中,需要根据实际情况做修改. 有个地方需要注意: 我这里刷新产生新的refreshToken时 旧的re ...
- .NET 6 OAuth2.0 IdentityServer4 4.X PasswordToken(创建Token) RefreshToken(刷新Token) RevokeToken(撤销Token
.NET Core OAuth IdentityServer4 AllowAnonymous Policy 白名单 .NET 5 IdentityServer4 4.X版本 jwt.io 最小 API ...
- accesstoken、refreshtoken
在工作的时候,有点疑惑accesstoken.refreshtoken这两个是怎么实现的,简单查找了一下百度,得到了如下的解释 1,token化的协议过程 2,当用户登录的时候,生成access_to ...
- refreshtoken用mysql_微信access_token和refresh_token保存于redis
此处以保存用户授权access_token为例,接口调用access_token可在项目启动时进行缓存.部分代码如下: @Autowired private RedisTemplate redisTe ...
- Java项目:在线考试系统(java+springBoot+vue+Mysql+maven)
源码获取:博客首页 "资源" 里下载! 管理员和教师登陆此账号就进入后台,学生登陆此账号就进入前端做题. 老师发布了考试,学生才可以在主页面看到相应的考试信息. 有考试安排表以后, ...
最新文章
- android编译产生的apk或so不安装 .
- 关于Android中XML解析方式
- Linux-0.00 代码解析(四)
- 报错, nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException
- 同学聚会后我主动埋单,回家后竟被同学们拉黑了,怎么办?
- 在不推动提交的情况下触发Travis-CI重建?
- JavaScript的可变参数介绍
- MySQL Workbench 导入导出乱码解决方法
- mac 安装android sdk
- oppok3如何刷机_oppok3刷机方法
- Oracle v$SQLAREA
- 驻点、极值点、拐点间的区别和联系
- 微服务:高性能网关 ShenYu简介
- 海湾gst5000主机消防广播_海湾GST5000消防主机常见问题及解决!
- 扫描建模在三维建模中有多厉害?
- 产品经理的职业生涯规划是怎么样的?
- POJ3255(次最短路)
- PAT_乙级1014
- 科技引领未来,银联开放平台诚邀你的加入
- 注册免费企业邮箱的方法
热门文章
- 计算机主板电池没电什么情况,电脑主板电池没电会怎样_电脑主板电池没电有什么后果如何解决...
- 实现一个通用的函数柯里化的函数
- 使用画笔 Stock Pens
- 微信公众号开发总结(Node.js + express + winston)
- 蓝桥杯-带分数(C语言)
- 如何给WORD文档加注释?
- 联通宽带桥接模式修改
- Pangle付款方式,Pangle付款时间?Pangle如何收款结汇?
- shell 脚本、 lua脚本
- 什么是KPI(关键业绩指标)?(转载)