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

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

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

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

使用refreshToken可以提高安全性

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

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

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

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

业务需求

在用户登录应用后,服务器会返回一组数据,其中就包含了accessTokenrefreshToken,每个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相关推荐

  1. refreshtoken用mysql_「SpringCloud」 Spring Security OAuth2 Mysql管理在线Token

    原标题:「SpringCloud」 Spring Security OAuth2 Mysql管理在线Token 前言:Spring Cloud 分布式中的登录如何可视化的管理目前下发的令牌.使用情况. ...

  2. Identityserver4中ResourceOwnerPassword 模式获取refreshtoken

    一.IS4服务端配置 1.配置Client new Client{ClientId = "xamarin",ClientSecrets = { new Secret("s ...

  3. 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 ...

  4. SpringSecurity OAuth2 (7) 自定义 AccessToken 和 RefreshToken (JWT with RSA 签名)

    文章目录 AuthorizationServer 引言 AuthorizationServerTokenServices ResourceServerTokenServices TokenStore ...

  5. accessToken refreshToken简单使用源码demo,双token刷新及有效时间设置

    最后会附上源码 这篇介绍了一个项目中使用的双token登录认证刷新的demo,如需移植到生产项目中,需要根据实际情况做修改. 有个地方需要注意: 我这里刷新产生新的refreshToken时 旧的re ...

  6. .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 ...

  7. accesstoken、refreshtoken

    在工作的时候,有点疑惑accesstoken.refreshtoken这两个是怎么实现的,简单查找了一下百度,得到了如下的解释 1,token化的协议过程 2,当用户登录的时候,生成access_to ...

  8. refreshtoken用mysql_微信access_token和refresh_token保存于redis

    此处以保存用户授权access_token为例,接口调用access_token可在项目启动时进行缓存.部分代码如下: @Autowired private RedisTemplate redisTe ...

  9. Java项目:在线考试系统(java+springBoot+vue+Mysql+maven)

    源码获取:博客首页 "资源" 里下载! 管理员和教师登陆此账号就进入后台,学生登陆此账号就进入前端做题. 老师发布了考试,学生才可以在主页面看到相应的考试信息. 有考试安排表以后, ...

最新文章

  1. android编译产生的apk或so不安装 .
  2. 关于Android中XML解析方式
  3. Linux-0.00 代码解析(四)
  4. 报错, nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException
  5. 同学聚会后我主动埋单,回家后竟被同学们拉黑了,怎么办?
  6. 在不推动提交的情况下触发Travis-CI重建?
  7. JavaScript的可变参数介绍
  8. MySQL Workbench 导入导出乱码解决方法
  9. mac 安装android sdk
  10. oppok3如何刷机_oppok3刷机方法
  11. Oracle v$SQLAREA
  12. 驻点、极值点、拐点间的区别和联系
  13. 微服务:高性能网关 ShenYu简介
  14. 海湾gst5000主机消防广播_海湾GST5000消防主机常见问题及解决!
  15. 扫描建模在三维建模中有多厉害?
  16. 产品经理的职业生涯规划是怎么样的?
  17. POJ3255(次最短路)
  18. PAT_乙级1014
  19. 科技引领未来,银联开放平台诚邀你的加入
  20. 注册免费企业邮箱的方法

热门文章

  1. 计算机主板电池没电什么情况,电脑主板电池没电会怎样_电脑主板电池没电有什么后果如何解决...
  2. 实现一个通用的函数柯里化的函数
  3. 使用画笔 Stock Pens
  4. 微信公众号开发总结(Node.js + express + winston)
  5. 蓝桥杯-带分数(C语言)
  6. 如何给WORD文档加注释?
  7. 联通宽带桥接模式修改
  8. Pangle付款方式,Pangle付款时间?Pangle如何收款结汇?
  9. shell 脚本、 lua脚本
  10. 什么是KPI(关键业绩指标)?(转载)