关于无感刷新Token,我是这样子做的
本文正在参加「金石计划 . 瓜分6万现金大奖」
什么是JWT
JWT
是全称是JSON WEB TOKEN
,是一个开放标准,用于将各方数据信息作为JSON格式进行对象传递,可以对数据进行可选的数字加密,可使用RSA
或ECDSA
进行公钥/私钥签名。
使用场景
JWT
最常见的使用场景就是缓存当前用户登录信息,当用户登录成功之后,拿到JWT
,之后用户的每一个请求在请求头携带上Authorization
字段来辨别区分请求的用户信息。且不需要额外的资源开销。
相比传统session的区别
比起传统的session
认证方案,为了让服务器能识别是哪一个用户发过来的请求,都需要在服务器上保存一份用户的登录信息(通常保存在内存中),再与浏览器的cookie
打交道。
- 安全方面 由于是使用
cookie
来识别用户信息的,如果cookie
被拦截,用户会很容易受到跨站请求伪造的攻击。 - 负载均衡 当服务器A保存了用户A的数据之后,在下一次用户A服务器A时由于服务器A访问量较大,被转发到服务器B,此时服务器B没有用户A的数据,会导致
session
失效。 - 内存开销 随着时间推移,用户的增长,服务器需要保存的用户登录信息也就越来越多的,会导致服务器开销越来越大。
为什么说JWT不需要额外的开销
JWT
为三个部分组成,分别是Header
,Payload
,Signature
,使用.
符号分隔。
// 像这样子
xxxxx.yyyyy.zzzzz
复制代码
标头 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失效// 判断本地是否有缓存有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);
};
关于无感刷新Token,我是这样子做的相关推荐
- 实现无感刷新token我是这样做的
大家好,我是漫步,今天来分享一个登录常常遇到的难题,即登录超时时间与安全性的纠结问题. 原文: https://juejin.cn/post/6983582201690456071 前言 最近在做需求 ...
- 实现无感刷新 token 我是这样做的
原文: https://juejin.cn/post/6983582201690456071 前言 最近在做需求的时候,涉及到登录token,产品提出一个问题:能不能让token过期时间长一点,我频繁 ...
- Laravel6通过jwt(tymon/jwt-auth)实现API用户无感刷新TOKEN
Laravel6通过jwt实现API用户无感刷新TOKEN 1.TOKEN是什么 2.jwt是什么 3.jwt安装&配置 3.1.通过composer安装 3.2.发布配置 3.3.生成加密密 ...
- 使用Axios进行无感刷新Token
前言 本人在开发项目时,在做登录模块时,参考了oauth2,在用户认证成功后会返回给前端一些令牌相关数据.接下来,再用进行接口请求时,前端根据令牌数据进行一系列的判断,然后做出最好的选择. 举个例子: ...
- Vue 无感刷新token
关于无感刷新的理解: 实现token无感刷新对于前端来说是一项非常常用的技术,其本质是为了优化用户体验,当token过期时不需要用户跳回登录页重新登录,而是当token失效时,进行拦截,发送刷新to ...
- token过期怎么办 无感刷新token
(1)可以通过响应拦截器或者全局前置守卫强制跳转登录页 // 全局前置守卫 router.beforeEach((to, from) => {let token = sessionStorage ...
- 无感刷新token方法
通常,对于一些需要记录用户行为的系统,在进行网络请求的时候都会要求传递一下登录的token.不过,为了接口数据的安全,服务器的token一般不会设置太长,根据需要一般是1-7天的样子,token过期后 ...
- uniapp 实现无感刷新token, 适应大多数项目
不管你是用taro uni 还是vue-cli 或者 react-cli 刷新token这块一通百通 本质上 都一样 我之前讲了一个是 在响应拦截哪里做token刷新 其实这样做还是不好的,因为这样我 ...
- 前端token知识梳理:token如何存储?token过期如何处理?如何无感刷新token?
在前后端是以token的形式交互,既然是token,那么肯定有它的过期时间(为了接口数据的安全,服务器的token一般不会设置太长,根据需要一般是1-7天的样子),没有一个token是永久的,永久的t ...
最新文章
- 编辑器的合并用不了_为什么图片和PDF合并后的PDF页面大小不一
- 这群“未来零售之星” 收到了一份意义非凡的新年大礼
- 基于Clang的缓存型C++编译器Zapcc开源
- 大数据数据收集数据困难_大数据架构、大数据开发与数据分析的区别
- 样机模型尺寸怎么改_土耳其五代机全尺寸样机模型首次亮相巴黎航展,这不是玩票,是一架认真设计的五代机!...
- n阶自相关matlab代码,随机信号及其自相关函数和功率谱密度的MATLAB实现.doc
- 深度学习在CTR中的应用
- 白云山脚下的廉价菜-饮胜酒家
- crmeb pc端模板下载_PC端人人影视下载速度如何提高
- 最详细的Fast RCNN论文笔记
- TS Interface
- 运行报错Error starting ApplicationContext
- primefaces教程_Primefaces Spring和Hibernate集成示例教程
- 第六节 静态的(static)和单例模式
- ios怎么下载java游戏平台_如何快速下载并安装 iOS 模拟器
- D-link 带USB口无线路由器 配置网络共享打印机
- 信息入口的新闻客户端如何盈利?
- linux卷影复制功能,vssadmin 卷影复制服务管理命令行工具
- Python自动化爬虫教程:Pyppeteer采集京东商城书籍信息
- nfc卡模式与标准模式_解析目前NFC具有的三种工作模式
热门文章
- 毕业论文评审意见、导师意见范文、模板
- 通电后第一次开机黑屏_为什么我的电脑第一次开机是黑屏,要开第二次才可以...
- adrv9003/ADRV9001/ADRV9002 FPGA驱动开发(硬件开发)
- etp服务器怎么连接共享文件夹,Everything共享文件操作方法
- mysql visio_Visio 2010对MySQL数据库反向工程生成ER数据库模型图
- 森林探险旅游开发模式初探(转)
- matlab vb调用,VB程序中实现调用MATLAB的方法
- 如何在ubuntu上安装QQ
- 前台到后台的一些问题
- AOP获取request各项参数操作