Posted in: 前端

jwt 无痛刷新最佳实践 axios版本

之前写过一片基于 “luch-request” 的jwt 无痛刷新最佳实践,反响不错,所以现在增加axios 版本,相对于之前,本次的设计更加简洁明了。

Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。

如果你还还是不了解什么是jwt,可以看看这篇文章:什么是 JWT — JSON WEB TOKEN

验证流程图

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTEwODUxNzI=,size_16,color_FFFFFF,t_70
jwt 验证流程图

实现思路

技术栈说明:

http 库使用了axios

single-promises

示例技术栈:vite、vue、pinia、js-cookie

后端模拟:express(模拟api,简单模拟,非真实jwt 架构)

字段说明:

access_token:普通token,过一段时间就会过期

refresh_token:用于刷新access_token

expire:access_token过期的时间,相对时间,不使用绝对时间是因为服务端时间和客户端时间可能有误差。比如有限时间只有5min,那这个值就应该为 5 * 60 * 1000 = 300000

请求前拦截验证

如果需要请求前拦截刷新,必须要有可以可以判断到本地access_token 失效的设计,如果你的后端没有提供可以判断的设计,那么只能使用响应拦截了

在示例项目中,我在请求前拦截使用了 access_token 的有效时间来判断本地token 是否失效。

因为在请求前已经可以通过判断expire过期时间来知道 access_token 是否过期了。可以在这里就进行拦截获取新的’access_token’了。获取到之后直接赋值新的access_token给header里的字段继续请求即可。

这里我们可以使用 `single-promise` 来阻塞请求,等待jwt 刷新api 的请求。

把刷新access_token 的方法使用 `single-promise` 包装,然后之后如果需要刷新,直接调用singlePromise 返回的函数。

还要考虑到 jwt 刷新失败的情况,如果刷新失败,我们可以直接放弃本次请求

直接在请求拦截器内部

return Promise.reject(new Error())

放弃本次请求,这样会进入响应拦截器的错误响应拦截。

如果需要在刷新accesToken 失败后重试几次,可以试试下方工具库包装一下刷新方法

https://github.com/sindresorhus/p-retry

在编写刷新accessToken api 的时候,可以考虑重新new 一个axios 实例,用于刷新,如果你的逻辑处理不好,可能会进入死循环,所以要谨慎。或者可以考虑把刷新accessToken api url 列入白名单,不需要accessToken

请求之后拦截

请求之后可以通过后端返回的code码知道是否为’access_token’过期,需要重新刷新access_token。

基本会有两种情况,access_token 失效了、refresh_token 失效了。

access_token 失效

刷新access_token 使用上方通过`single-promise` 包装的函数,保证只有一个api 在调用。

如果需要,在这里获取新的access_token后,重新发起本次请求。

需要注意:重新发起请求时可以考虑重新new 一个axios 实例,用于重试,否则,如果你的逻辑处理不谨慎,可能会进入死循环。

需要注意的是,在多个请求同时发起时,有可能请求响应比获取新的access_token还要慢,我们要处理这种情况。

比如同时发起5个请求,前3个响应后重新刷新accessToken,刷新成功后,后2个请求才响应accessToken 过期的状态码,此时,本地的accessToken 其实已经是新的了,我们没必要再次刷新accessToken。

同样,在这里,我们需要考虑access_token 刷新失败的情况。

刷新accessToken 后,重试当前请求

  try {
          response = await instance.request(response.config)
        } catch (e) {
          return Promise.reject(e)
        }

让响应拦截器的response 等于重试后的response

同样,这里也要考虑重试失败的情况,如果失败,直接进入catch

refresh_token 失效

如果refresh_token 失效,说明已经无法刷新token 了,需要用户重新登录。

本次分享已全部完毕。

示例

可以观看下方视频,演示了多种情况。

如果你需要示例项目,可以打赏作者,请作者喝个奶茶,6yuan以上就可。

wechat 打赏支付宝打赏

打赏时可在备注说明:`${你的邮箱地址} 619`,

或者打赏后联系本人。

也可在“爱发电”在线支付,自动回复里会有密码,地址:jwt 无痛刷新最佳实践示例(axios 版本)

联系方式:

邮箱:webwork.s@qq.com

qq: 370306150

获取示例地址:jwt 无痛刷新最佳实践axios 版本:付费示例下载

打赏后本人会把文章访问密码发给你。邮箱和qq 回复有延迟。

订阅
提醒
guest

2 评论
最新
最早的 投票最多的
在线反馈
显示所有评论
Back to Top