处理 JWT 的过期机制并结合刷新 Token 实现无缝登录是一个常见的需求。为了防止用户频繁登录,同时保持安全性,通常会使用短期有效的访问 Token(Access Token)和长期有效的刷新 Token(Refresh Token)来平衡两者。下面将逐步介绍如何实现这一机制。
访问 Token 和刷新 Token 的基本概念
**访问 Token (Access Token)**:用于验证用户的身份,并授予访问资源的权限。它通常短期有效(如 15 分钟至 1 小时),以减少长期暴露的安全风险。
**刷新 Token (Refresh Token)**:用于在访问 Token 过期后,获取新的访问 Token。它具有较长的有效期(如几天或几周),并仅在服务端存储或安全地处理,用户无法直接使用它来访问资源。
基本流程
- 用户登录:用户通过用户名和密码或其他认证方式登录,服务器验证通过后,生成并返回一个 访问 Token 和一个 刷新 Token。
- 使用访问 Token 访问资源:在访问受保护的资源时,用户每次请求都需要携带访问 Token(通常放在 HTTP Header 中)。
- 访问 Token 过期后刷新:当访问 Token 过期时,前端通过携带刷新 Token 向后端请求新的访问 Token,而无需再次登录。
- 刷新 Token 过期后重新登录:如果刷新 Token 也过期,则需要用户重新登录。
刷新 Token 的安全性
- 刷新 Token 存储:刷新 Token 不应该暴露在前端的存储中。建议存储在 HttpOnly Cookie 中,这样客户端无法通过 JavaScript 访问刷新 Token,减少了被攻击者盗取的可能。
- 刷新 Token 的双 Token 校验:为了进一步增强安全性,服务端可以在数据库中记录刷新 Token 的状态,并且要求前端每次刷新时提供当前 Token 和设备标识等信息。
- 刷新 Token 黑名单机制:当用户登出或刷新 Token 被滥用时,可以将对应的刷新 Token 标记为无效,避免被盗用。
完整的流程图
graph TD
A[用户登录] --> B[返回 Access Token 和 Refresh Token]
B --> C[用户使用 Access Token 访问资源]
C --> D{Access Token 是否过期?}
D -- 否 --> C
D -- 是 --> E[请求刷新 Token]
E --> F[使用 Refresh Token 获取新 Access Token]
F --> C
F --> G{Refresh Token 是否过期?}
G -- 否 --> F
G -- 是 --> H[用户重新登录]
C --> I[登出]
I --> J[使 Refresh Token 失效]
注意事项
- 短期 Token 的有效期:建议将访问 Token 的有效期设定得较短,例如 15-60 分钟,这样可以减少长期有效的 Token 被盗用后造成的风险。
- 刷新 Token 的有效期:刷新 Token 可以设为几天到几周,但也需要根据安全策略来定期更新或使其失效。
- 防止 Replay 攻击:刷新 Token 建议只使用一次,刷新 Token 后应颁发新的刷新 Token,旧的应作废。
双token怎么处理用户权限改变
将权限信息(包括限时权限的有效期)直接写入 JWT 中,然后在权限提升或变更时,用户通过刷新 Token 来重新申请授权。这样,大多数请求不需要频繁查询权限数据库,同时通过刷新机制保证了权限变更后的有效性。
将权限信息嵌入 JWT
在 Token 中直接嵌入用户的权限信息和临时权限的有效期,JWT 可以包含以下几个关键字段:
- 用户基本信息:如
user_id
、username
等。 - 权限信息:用户所拥有的所有权限(包括普通权限和临时权限)。
- 权限有效期:针对临时权限,可以在 JWT 中嵌入其具体的过期时间。
- **签发时间(iat)**和**过期时间(exp)**:JWT 标准的签发时间和有效期,用于 Token 的生命周期管理。
这样,每次用户发送请求时,微服务或网关只需解析 JWT 即可校验用户的权限,无需频繁查询数据库,极大提高了性能。
权限提升时刷新 Token
当用户权限发生提升或变更时,可以触发 Token 刷新机制:
- 当用户获得新的权限(例如更高级别的访问权限),需要刷新 Token 以将这些新权限包含在新的授权 Token 中。
- 可以通过两种方式触发 Token 刷新:
- 自动刷新:当权限提升时,系统通过某种机制(如消息队列或后台作业)通知客户端刷新 Token。
- 手动刷新:用户主动触发刷新 Token 的请求,例如通过应用界面的提示,或者当某些高级功能需要新权限时,用户会被要求重新登录或刷新 Token。
JWT 的过期时间与临时权限控制
- 对于普通的长期权限,JWT 中可以直接记录用户的权限列表。
- 对于临时权限,JWT 中可以设置一个权限的过期时间(比如一个
expires_at
字段),表示该权限在某个时间点之后会失效。通过这种方式,系统可以自动在 Token 的有效期内检查和控制临时权限的有效性。 - 细粒度的权限管理:通过将临时权限的有效期嵌入 Token,微服务在每次请求时只需要解析 Token 中的权限和有效期,判断当前时间是否超过权限的有效期,从而动态管理权限的生效和失效。
QA
Q: 既然刷新 Token 建议只使用一次,那为什么不抛弃刷新 Token 只使用短期 Token 呢
在设计使用 双 Token 机制 时,使用 短期访问 Token (Access Token) 和 单次有效的刷新 Token (Refresh Token) 有其独特的优势。让我们从以下几个角度来解释为什么不完全依赖短期 Token,而是采用双 Token 机制。
用户体验 vs 安全性
- 单独使用短期 Token:如果你只使用短期有效的 Token(比如每 15 分钟过期),那么在每个 Token 过期时,用户都必须重新登录以获取新的 Token。这会极大影响用户体验,特别是在用户长时间使用系统的场景下,如访问一个长时间未操作的页面,Token 过期后强制登录会打断用户的使用流程。
- 双 Token 机制:通过使用一个长期有效的刷新 Token,用户无需频繁登录。刷新 Token 可以在访问 Token 过期时,自动为用户生成新的访问 Token,而用户在前端并不会感知到这个过程,从而实现 无缝登录。
防止 Replay 攻击的必要性
- Replay 攻击 是指攻击者截获并重复使用用户的认证信息(如 Token)以非法访问系统。在双 Token 机制下,如果刷新 Token 是多次有效的,一旦被攻击者截获,他们就可以反复使用该刷新 Token 来生成新的访问 Token,从而长期保持对系统的访问权限。
- 单次使用的刷新 Token:为防止这种情况,采用单次有效的刷新 Token 策略,即每当客户端成功使用刷新 Token 获取新的访问 Token 后,服务端会生成一个新的刷新 Token,并废弃旧的刷新 Token。这样,即便攻击者截获了旧的刷新 Token,由于它已经被标记为无效,无法再用来生成新的访问 Token。
为什么不直接只用短期 Token?
假设我们完全抛弃刷新 Token,而只依赖短期访问 Token,这会带来几个问题:
- 用户频繁登录:短期 Token 的过期时间通常较短(如 15 分钟)。如果只使用短期 Token,一旦 Token 过期,用户就必须重新登录系统。对于用户来说,这是一个不便和负担。
- 安全性与用户体验的平衡:双 Token 机制允许我们通过短期的访问 Token 来限制 Token 暴露的风险,同时使用较长期的刷新 Token 来避免频繁登录。这样,访问 Token 可以频繁更换,提高安全性,而刷新 Token 则在必要时更新,提供一种平衡机制。
双 Token 机制的流程
假设我们启用了 单次有效的刷新 Token 策略,整个认证过程可以是这样的:
- 用户通过用户名和密码登录系统,服务器返回一个短期的 访问 Token 和一个长期的 刷新 Token。
- 用户使用访问 Token 访问资源,当访问 Token 过期时,前端会自动使用刷新 Token 请求新的访问 Token。
- 在使用刷新 Token 成功获取新的访问 Token 后,服务器返回一个新的刷新 Token,并使旧的刷新 Token 无效。
- 如果刷新 Token 也过期或被攻击者滥用,用户需要重新登录。
这样,每次刷新操作都会更新刷新 Token,同时旧的 Token 失效。即使攻击者截获了之前的 Token,它们也只能使用一次,并且无法长期滥用。
使用双 Token 机制的优势
- 减少频繁登录:用户体验更好,避免频繁要求用户重新登录。
- 提升安全性:通过短期的访问 Token 限制 Token 被盗用的时间窗口,同时通过刷新 Token 的单次使用机制防止 Replay 攻击。
- 防止长期滥用:即使攻击者截获了某个刷新 Token,由于它是单次有效的,攻击者无法通过重复使用刷新 Token 长期滥用系统。
总结
双 Token 机制通过结合短期访问 Token 和单次使用的刷新 Token 提供了一个平衡的方案,既能提高用户体验,又能保证安全性。虽然刷新 Token 建议只使用一次,但它的存在是为了在保证安全的前提下减少用户的登录次数,而不是完全抛弃它。
如何进行用户的权限验证
在双 Token 机制下进行用户的权限验证,需要结合访问 Token (Access Token) 和刷新 Token (Refresh Token) 来确保安全性和高效性。以下是详细的解释:
双 Token 的角色
- **访问 Token (Access Token)**:主要用于快速鉴权和授权,包含用户的基本身份信息和权限信息。通常是短期有效的,例如 15 分钟或 30 分钟。
- **刷新 Token (Refresh Token)**:用于在访问 Token 过期时,生成新的访问 Token。它不包含用户的权限信息,通常是长期有效的,但需要在某些情况下失效(如用户登出、修改密码等)。
双 Token 机制下,用户的权限验证主要通过访问 Token进行,而刷新 Token只负责获取新的访问 Token,不直接用于权限验证。
权限验证流程
在双 Token 机制下,用户权限验证的典型流程如下:
- 用户登录,服务器生成两个 Token:
- 一个短期的访问 Token,包含用户的身份信息和权限信息。
- 一个长期的刷新 Token,用于在访问 Token 失效时获取新的访问 Token。
- 用户携带访问 Token 访问受保护的资源:
- 用户在每次请求时,将访问 Token 通过 HTTP 头(通常是
Authorization: Bearer <access_token>
)传递给服务器。 - 服务器在收到请求后,验证访问 Token 的签名、是否过期、以及其包含的权限信息(例如用户的角色、具体权限等)。
- 用户在每次请求时,将访问 Token 通过 HTTP 头(通常是
- 服务器验证 Token 并授权:
- 服务器解析访问 Token,验证其中包含的用户身份和权限信息。
- 根据解析的权限信息,决定用户是否有权执行当前操作。如果权限验证通过,服务器继续处理业务逻辑,否则返回 403(Forbidden)。
- 访问 Token 过期:
- 如果访问 Token 过期,前端会携带刷新 Token 访问专门的刷新接口,服务器验证刷新 Token 的有效性后,重新颁发新的访问 Token 和刷新 Token。
- 刷新后的访问 Token 中会包含更新的权限信息,确保用户的权限是最新的。
- 权限信息更新:
- 如果用户的角色或权限发生变化(例如用户被赋予新权限,或权限被收回),刷新 Token 可以生成新的访问 Token,并将最新的权限信息带入新的访问 Token 中。
- 对于长时间使用的用户,权限变化可能不会立即反映在当前的访问 Token 上,但当下一个访问 Token 被刷新时,新权限将生效。
- 用户登录,服务器生成两个 Token:
双 Token 机制下的权限验证策略
Token 中包含权限信息
访问 Token 通常是自包含的,也就是说,所有需要的信息都嵌入在 Token 内,包括用户身份、角色、权限等。这可以通过 JWT 的
payload
部分来实现,典型的 JWT 可能包含如下信息:1
2
3
4
5
6
7
8
9{
"sub": "user123", // 用户 ID
"role": "admin", // 用户角色
"permissions": [ // 权限信息
"read:data",
"write:data"
],
"exp": 1700000000 // 过期时间
}服务器只需要解析访问 Token 的 payload,直接从中获取用户的权限信息,判断是否允许访问特定资源。
在数据库中存储权限信息
虽然访问 Token 中可以包含权限信息,但这些权限可能会随时间动态变化。例如,用户的角色被调整,或者新的权限被赋予用户。因此,部分系统设计中,Token 中只包含用户的身份信息(如用户 ID),权限信息则在每次请求时,从数据库或权限管理系统中动态查询。
- 优点:实时性更强,用户权限的任何变更都能立即生效,尤其适合那些权限经常调整的系统。
- 缺点:需要增加额外的数据库查询,可能会对性能造成影响,特别是在高并发场景下。
混合策略
一种常见的策略是使用混合方式:
- Token 中包含基本权限信息:如用户的角色和基础权限。
- 数据库查询进行细粒度权限验证:对于特定操作,如果权限要求较为复杂或动态调整较多,可以在访问时,从数据库中查询细粒度的权限信息。
这种方式能够平衡性能和实时性需求。
权限验证中的特殊处理场景
- 刷新 Token 被盗用
如果刷新 Token 被攻击者获取,攻击者可以使用它不断刷新新的访问 Token,进而长期访问系统。因此,以下几种方式可以提高安全性:
- 设置刷新 Token 的过期时间:虽然刷新 Token 通常比访问 Token 有更长的有效期,但它也应有一定的过期时间。
- 单次有效刷新 Token:每次使用刷新 Token 后,服务器生成新的刷新 Token,并废弃旧的刷新 Token,避免被截获后重复使用。
- IP 地址或设备绑定:在颁发刷新 Token 时,记录用户的 IP 地址或设备信息,刷新时验证这些信息是否一致。
- Token 黑名单机制
当用户主动登出、权限被撤销或刷新 Token 被发现泄露时,服务器可以将该 Token 加入黑名单,即使它在有效期内也无法再使用。
- 在访问时,系统检查该 Token 是否在黑名单内,如果在,则拒绝访问。
- 权限变更时的处理
- 实时更新:如果用户的权限在系统中发生变化,可以通过某种方式(如在刷新 Token 时)通知客户端获取新的访问 Token,以反映最新的权限信息。
- 批量失效:系统可以批量失效与某个用户相关的所有 Token(访问 Token 和刷新 Token),强制用户重新登录以更新权限。
权限验证流程总结
- 初次登录时,服务器颁发访问 Token 和 刷新 Token,访问 Token 包含用户的身份信息和权限信息。
- 用户请求资源时,携带访问 Token,服务器验证 Token 的有效性和权限信息。
- 访问 Token 过期后,前端携带刷新 Token 向服务器请求新的访问 Token,并更新权限信息。
- 权限变更时,新的权限信息会在下一次刷新 Token 时反映在新的访问 Token 中,确保权限同步。
- 如果用户的 Token 失效或被攻击者滥用,可以通过黑名单机制或单次刷新机制确保系统安全。