当前位置: 首页 > 知识库问答 >
问题:

jwt - JWT引入后的问题及优化方案:无感续签与token失效管理?

宰父涵忍
2024-05-13

引入JWT所带来的问题:

  1. token到期后需要无感续签;
    目前主流方案是采用双token机制,accessToken访问令牌、refreshToken刷新令牌;
  2. 已签发的token服务端无法主动将其失效;
    场景1:用户退出登录 (需要将该次登录签发的accessToken和refreshToken同时失效);
    场景2:用户修改密码、服务端修改了某个用户具有的权限或者角色、用户的帐户被封禁/删除。。。。; (需要将该用户签发的所有token都失效);

    目前网上大多数方案是使用黑名单机制,直接将accessToken存到黑名单并设置过期时间;
    但是这样还是有其他问题并未解决。

    首先,签发出去的accessToken和refreshToken之间没有关联关系,用户退出登录时无法同时将refreshToken也失效。
    其次,用户密码泄露被别人恶意登录,用户紧急修改密码。由于不知道当前签发了哪些token,无法使其全部都失效
    (有一个方案是每个用户单独有自己的secretKey,改密码后直接将secretKey变更,但是这种方案验签时每次都要先从数据库查询出secretKey,成本太高)。
    再次,由于JWT生成的token一般都比较长,直接将其存到缓存对内存占用也比较大。

由此对第2点做如下优化:
这里依然使用黑名单机制,不过额外再引入两个字段(token序列号,token批次号),token序列号作为关联此次登录的accessToken和refreshToken,token批次号作为关联密码变更前签发的所有token。

  1. 在系统增加一个全局自增变量(由Redis自增incr)作为token序列号,暂时命名为tokenSeqNum
  2. 在数据库user表中增加一个字段tokenBatchNum作为token批次号。
  3. 用户登录成功时,tokenSeqNum全局incr,从user表中取到当前用户的tokenBatchNum; 将username、tokenSeqNum、tokenBatchNum添加到JWT的payload中。
  4. 用户退出登录时,从accessToken中解析出username、tokenSeqNum,拼接username_tokenSeqNum做为缓存key存入Redis黑名单,并设置过期时间。
  5. 用户修改密码时,从user表中取到了用户当前的tokenBatchNum,更新用户表时同时更新tokenBatchNum = tokenBatchNum + 1,拼接username_tokenBatchNum做为缓存key存入Redis黑名单,并设置过期时间。
  6. 用户请求受保护资源、或请求刷新token时,进行黑名单校验; 首先从token中解析出username、tokenSeqNum、tokenBatchNum;
    如果用户操作了退出登录,则username_tokenSeqNum存在黑名单中,判断为签名已失效;
    如果用户修改了密码,则username_tokenBatchNum存在黑名单中,判断为签名已失效;

如此。既可以解决关联失效问题,又能节省内存空间。

关于以上想法,欢迎大家一起探讨是否可行。

共有1个答案

武卓
2024-05-13

引入JWT所带来的问题及优化方案:

问题一:token到期后需要无感续签

解决方案
采用双token机制是一种有效的解决方案。accessToken用于访问资源,而refreshToken用于在accessToken过期时获取新的accessToken,无需用户重新登录。

问题二:已签发的token服务端无法主动将其失效

目前问题

  • 签发出去的accessTokenrefreshToken之间没有关联关系,导致用户退出登录时无法同时将refreshToken失效。
  • 用户密码泄露后,无法使所有已签发的token失效。
  • JWT生成的token较长,直接存到缓存中内存占用大。

优化方案
引入黑名单机制结合token序列号与批次号的方案是可行的,可以解决上述问题。

  1. 全局自增变量作为token序列号:确保每次登录的accessTokenrefreshToken都有唯一的序列号关联。
  2. token批次号管理:当用户修改密码时,更新批次号,这样可以通过批次号来使所有旧的token失效。
  3. 黑名单校验:在每次请求校验token时,除了正常的JWT校验外,还需要校验token是否在黑名单中。

优化方案优势

  • 解决了accessTokenrefreshToken之间的关联失效问题。
  • 通过批次号管理,可以方便地使所有旧的token失效,解决了密码泄露的风险。
  • 使用username_tokenSeqNumusername_tokenBatchNum作为缓存key,可以有效节省内存空间。

注意事项

  • 需要确保Redis等存储黑名单的系统可靠且性能足够。
  • 在黑名单中设置合理的过期时间,避免无效数据长期占用存储空间。
  • 在实现过程中,要确保所有token的签发、校验和失效操作都是线程安全的。

综上所述,您提出的优化方案是可行的,能够解决JWT引入后的一些问题,并有效地管理token的失效。当然,具体实现时还需要根据实际情况进行调整和优化。

 类似资料:
  • 我正在尝试手动创建ES256 JWT令牌。我有一个用python编写的小脚本,它对使用ecdsa python的sha256哈希进行签名。但签名在jwt上无效。木卫一。 繁殖步骤: 创建Base64报头负载: eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9。EYJZDWIixMJ0Nty3ODKwiiBmFtzSi6IkPvAg4GrG9LiiWiyWrTaw4Ionry

  • 本文向大家介绍在node中使用jwt签发与验证token的方法,包括了在node中使用jwt签发与验证token的方法的使用技巧和注意事项,需要的朋友参考一下 1.什么是token token的意思是“令牌”,是服务端生成的一串字符串,作为客户端进行请求的一个标识。 token是在服务端产生的。如果前端使用用户名和密码向服务端发送请求认证,服务端认证成功,那么在服务端会返回token给前端。 前端

  • 我已经通过浏览器中的令牌读取访问敏感的Spring引导执行器endpoint,因为它接近我需要的,但我不一定需要浏览器,这个问题没有答案。 与教程相反,我在pom.xml中包含了spring-boot-starter-actuator作为依赖项。 我的application.properties如下所示: 我的AccountUserDetailsService如下所示: 我包含了角色“role_a

  • 概念 什么是认证(Authentication) 通俗地讲就是验证当前用户的身份,证明“你是你自己” 互联网中的认证: 用户名密码登录 邮箱发送登录链接 手机号接收验证码 只要你能收到邮箱/验证码,就默认你是账号的主人 什么是授权(Authorization) 用户授予第三方应用访问该用户某些资源的权限 你在安装手机应用的时候,APP 会询问是否允许授予权限(访问相册、地理位置等权限) 实现授权的

  • 我正在使用Azure AD对spring boot应用程序进行用户身份验证。我创建了一个应用程序来获取登录用户的访问令牌(令牌创建者应用程序)。在此应用程序中,“/token”API从@RegisteredAuth2AuthorizedClient读取访问令牌,并返回与响应相同的令牌。 然后,我必须使用返回的令牌作为RESTAPI的承载令牌,用于具有相同客户端id和相同配置的另一个应用程序。 但当

  • 编辑: 阅读有关bug的讨论:https://github.com/tymondesigns/jwt-auth/issues/83 我原来的问题是: 我正在使用jwt auth my protected resources实现,该资源需要经过身份验证的用户,代码如下: 当用户在API上登录时,将创建一个授权令牌,并将响应授权标头发送到调用资源的客户端应用程序。因此,客户端应用程序在截获任何响应的头