本文正在参加「金石计划 . 瓜分6万现金大奖」

什么是JWT

JWT是全称是JSON WEB TOKEN,是一个开放标准,用于将各方数据信息作为JSON格式进行对象传递,可以对数据进行可选的数字加密,可使用RSAECDSA进行公钥/私钥签名。

使用场景

JWT最常见的使用场景就是缓存当前用户登录信息,当用户登录成功之后,拿到JWT,之后用户的每一个请求在请求头携带上Authorization字段来辨别区分请求的用户信息。且不需要额外的资源开销。

相比传统session的区别

比起传统的session认证方案,为了让服务器能识别是哪一个用户发过来的请求,都需要在服务器上保存一份用户的登录信息(通常保存在内存中),再与浏览器的cookie打交道。

  • 安全方面 由于是使用cookie来识别用户信息的,如果cookie被拦截,用户会很容易受到跨站请求伪造的攻击。
  • 负载均衡 当服务器A保存了用户A的数据之后,在下一次用户A服务器A时由于服务器A访问量较大,被转发到服务器B,此时服务器B没有用户A的数据,会导致session失效。
  • 内存开销 随着时间推移,用户的增长,服务器需要保存的用户登录信息也就越来越多的,会导致服务器开销越来越大。

为什么说JWT不需要额外的开销

JWT为三个部分组成,分别是HeaderPayloadSignature,使用.符号分隔。

// 像这样子
xxxxx.yyyyy.zzzzz
复制代码

标头 header

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

{"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

refreshTokenOauth2认证中的一个概念,和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)

业务需求

在用户登录应用后,服务器会返回一组数据,其中就包含了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);
};

关于无感刷新Token,我是这样子做的相关推荐

  1. 实现无感刷新token我是这样做的

    大家好,我是漫步,今天来分享一个登录常常遇到的难题,即登录超时时间与安全性的纠结问题. 原文: https://juejin.cn/post/6983582201690456071 前言 最近在做需求 ...

  2. 实现无感刷新 token 我是这样做的

    原文: https://juejin.cn/post/6983582201690456071 前言 最近在做需求的时候,涉及到登录token,产品提出一个问题:能不能让token过期时间长一点,我频繁 ...

  3. Laravel6通过jwt(tymon/jwt-auth)实现API用户无感刷新TOKEN

    Laravel6通过jwt实现API用户无感刷新TOKEN 1.TOKEN是什么 2.jwt是什么 3.jwt安装&配置 3.1.通过composer安装 3.2.发布配置 3.3.生成加密密 ...

  4. 使用Axios进行无感刷新Token

    前言 本人在开发项目时,在做登录模块时,参考了oauth2,在用户认证成功后会返回给前端一些令牌相关数据.接下来,再用进行接口请求时,前端根据令牌数据进行一系列的判断,然后做出最好的选择. 举个例子: ...

  5. Vue 无感刷新token

    关于无感刷新的理解:  实现token无感刷新对于前端来说是一项非常常用的技术,其本质是为了优化用户体验,当token过期时不需要用户跳回登录页重新登录,而是当token失效时,进行拦截,发送刷新to ...

  6. token过期怎么办 无感刷新token

    (1)可以通过响应拦截器或者全局前置守卫强制跳转登录页 // 全局前置守卫 router.beforeEach((to, from) => {let token = sessionStorage ...

  7. 无感刷新token方法

    通常,对于一些需要记录用户行为的系统,在进行网络请求的时候都会要求传递一下登录的token.不过,为了接口数据的安全,服务器的token一般不会设置太长,根据需要一般是1-7天的样子,token过期后 ...

  8. uniapp 实现无感刷新token, 适应大多数项目

    不管你是用taro uni 还是vue-cli 或者 react-cli 刷新token这块一通百通 本质上 都一样 我之前讲了一个是 在响应拦截哪里做token刷新 其实这样做还是不好的,因为这样我 ...

  9. 前端token知识梳理:token如何存储?token过期如何处理?如何无感刷新token?

    在前后端是以token的形式交互,既然是token,那么肯定有它的过期时间(为了接口数据的安全,服务器的token一般不会设置太长,根据需要一般是1-7天的样子),没有一个token是永久的,永久的t ...

最新文章

  1. 编辑器的合并用不了_为什么图片和PDF合并后的PDF页面大小不一
  2. 这群“未来零售之星” 收到了一份意义非凡的新年大礼
  3. 基于Clang的缓存型C++编译器Zapcc开源
  4. 大数据数据收集数据困难_大数据架构、大数据开发与数据分析的区别
  5. 样机模型尺寸怎么改_土耳其五代机全尺寸样机模型首次亮相巴黎航展,这不是玩票,是一架认真设计的五代机!...
  6. n阶自相关matlab代码,随机信号及其自相关函数和功率谱密度的MATLAB实现.doc
  7. 深度学习在CTR中的应用
  8. 白云山脚下的廉价菜-饮胜酒家
  9. crmeb pc端模板下载_PC端人人影视下载速度如何提高
  10. 最详细的Fast RCNN论文笔记
  11. TS Interface
  12. 运行报错Error starting ApplicationContext
  13. primefaces教程_Primefaces Spring和Hibernate集成示例教程
  14. 第六节 静态的(static)和单例模式
  15. ios怎么下载java游戏平台_如何快速下载并安装 iOS 模拟器
  16. D-link 带USB口无线路由器 配置网络共享打印机
  17. 信息入口的新闻客户端如何盈利?
  18. linux卷影复制功能,vssadmin 卷影复制服务管理命令行工具
  19. Python自动化爬虫教程:Pyppeteer采集京东商城书籍信息
  20. nfc卡模式与标准模式_解析目前NFC具有的三种工作模式

热门文章

  1. 毕业论文评审意见、导师意见范文、模板
  2. 通电后第一次开机黑屏_为什么我的电脑第一次开机是黑屏,要开第二次才可以...
  3. adrv9003/ADRV9001/ADRV9002 FPGA驱动开发(硬件开发)
  4. etp服务器怎么连接共享文件夹,Everything共享文件操作方法
  5. mysql visio_Visio 2010对MySQL数据库反向工程生成ER数据库模型图
  6. 森林探险旅游开发模式初探(转)
  7. matlab vb调用,VB程序中实现调用MATLAB的方法
  8. 如何在ubuntu上安装QQ
  9. 前台到后台的一些问题
  10. AOP获取request各项参数操作