JWT 与会话认证
了解基于会话和 JWT 认证之间的差异。探索权衡点、优势和用例以为你的应用选择合适的认证方案。
通常来说,使用应用程序的第一步是认证,用户提供身份凭证以成功登录。在这一步之后,身份系统(即身份提供者,认证服务器等)即可知道用户是谁以及他们有权访问哪些资源。
由于 HTTP 本质上是无状态的,会话中的每个请求都是独立的,不会记住之前请求的信息。为每一个操作重新认证用户是繁琐的,并且损害了用户体验。
接下来我们来了解 基于会话的认证 和 JWT (JSON Web Tokens) 认证,这两种方法都是保持认证状态的流行手段。每种方法都有其独特的优势和权衡点,两者之间的选择取决于你的应用程序的具体需求。如果你正在这两者之间做出选择,那么这篇指南可以帮到你。
什么是基于会话的认证?
基于会话的认证依赖于 服务器 维护用户的认证状态记录。通过创建和管理会话,服务器使用户能够在不必每次请求都重新输入凭证的情况下,继续登录并与应用程序交互。
基于会话的认证如何工作?
会话创建
- 用户认证并提供一些凭证(例如,电子邮件和密码)。
- 如果凭证有效,服务器创建一个持久的记录表示该 会话。会话包括信息如随机字符串、用户标识符、会话开始时间、会话过期时间等。
SessionID
存储在数据库中,并作为cookie 返回给用户的客户端。
会话验证
- 该过程可以由用户手动触发(例如,点击标签页,刷新页面)或由客户端自动触发(例如,在初始页面加载期间或通过 API 调用
SessionID
)。 - 每个后续调用从客户端发送一个包含会话cookie的 HTTP 请求到服务器。
- 服务器通过查看存储在服务器上的会话数据来验证
SessionID
。 - 如果有效,服务器处理请求并授权用户。
如何撤销会话?
会话可以实时失效,这在需要快速撤销访问的情况下十分方便。
- 用户手动注销:服务器删除会话记录,实际上将用户注销。
- 管理员强制用户注销:管理员或系统可以通过从数据库中删除特定会话来终止会话。例如,在安全漏洞期间。
- 会话过期:会话可以在一段不活跃的持续时间后或设置的时间限制后自动过期。
基于会话认证的优势
- 简单可靠:会话记录提供了明确的、集中的来源,允许更高程度的信任并使授权决策更可靠。
- 实时撤销:通过删除或失效会话记录,用户的访问可以快速被撤销。
基于会话认证的劣势
- 分布式系统中的延迟:在多个服务器之间进行会话数据的维护总是需要同步会话存储。这引入了附加的延迟,因为服务器每次请求必须检查会话存储。
- 高资源消耗:每个会话占用服务器资源,当用户基数扩大时,影 响性能。
- 安全风险:会话劫持(通过被盗的会话 cookie)可能允许未经授权的访问用户账户。
- 对 API 用途有限:基于会话的认证不适合移动应用。由于会话数据存储在服务器上,当用户数量较多时会增加负载和复杂性。此外,它使用的 cookie 在移动设备上较难处理。
什么是 JWT 认证?
JSON Web Tokens (JWTs) 采取不同的方法,通过使用 JSON 对象将所有相关的用户信息直接嵌入到一个令牌中。与基于会话的方法不同,JWT 是无状态的,意味着服务器不管理认证记录。
JWT 认证如何工作?
一个 JWT 包含三部分:一个头、负载和签名。
- 头包含签名算法(例如,HS256)和令牌的类型(JWT)。
- 负载包含核心声明,例如用户身份、用户角色和过期时间。
- 签名使用密钥签署头和负载,允许验证签名是否被篡改。
JWT 发行
- 客户端向认证服务器发送用户凭证(统一身份提供者特别有利于跨多个域管理访问)。
- 认证成功后,服务器生成包含头、负载和签名的 JWT。
- 认证服务器将发出的令牌发送给客户端。客户端存储 JWT(例如,存储在 cookies、localStorage 或 sessionStorage 中)。
基于会话的工作流遵循类似的过程。然而,在认证之后,用户信息存储在服务器的会话中,而 JWT 依赖于发送给客户端以进行存储和后续使用的令牌。
令牌验证
- 对于后续的 API 请求,客户端在
Authorization
头中发送 JWT (Bearer <token>
)。 - 服务器使用秘密或公钥验证 JWT 的签名并检查其声明(例如,过期时间、发行者)。
- 如果令牌有效,服务器授予客户端访问请求资源的权限。
基于会话的认证要求服务器查询会话存储,这可能很慢,特别是如果它依赖于外部或集中化的数据库。相比之下,JWT 认证是无状态的,所有必要的信息都存储在客户端令牌中,并利用签名确保安全。这消除了会话管理的需要,使其更快速且更易于扩展,特别是在分布式系统中。
如何撤销 JWT?
在客户端,注销通常意味着清除本地会话并从存储中移除令牌(ID 令牌、访问令牌、刷新令牌)。然而,对于 JWT 认证,这只是在本地解除用户的登录,而集中化的会话在授权服务器上仍然保持有效。因此,直到令牌过期或被手动终止,用户可能仍可以访问同一会话下的其他应用程序。
撤销 JWT (JSON Web Token) 比基于会话的认证更具挑战性,因为 JWT 是无状态的,一旦发出便无法失效,除非实施特定的策略。常见方法包括:
- 短期过期时间:为 JWT 设置一个短的
exp
声明(例如,15 分钟)。一旦过期,用户必须重新认证。如果令牌被泄露,这会将风险降到最小,因为攻击者只能在有限的时间内使用该令牌。为了保持无缝的用户体验,刷新令牌 可以用来减少重新认证的不便。 - 令牌黑名单:在关键情况下(例如,用户注销,密码更改),维护一个撤销令牌的黑名单。服务器检查传入的令牌是否在该黑名单中,并拒绝任何匹配项。虽然有效,但这种方法要求追踪撤销的令牌,这与 JWT 的无状态性质相违背,并且如果列表变得过大可能变得低效。
- 撤销端点:在授权服务器上引入一个撤销端点,可以使令牌(例如,刷新令牌)失效。一旦刷新令牌被撤销,任何从它发出的访问令牌将不再被续期。这种方法在 OAuth2 流程中效果很好。
JWT 认证的优势
- 快速且信息丰富:JWT 自包含的性质使客户端验证更快更高效,无需服务器交互。它们还可以在令牌中包含自定义声明(例如,用户角色或其他相关数据),使服务器可以不需要查询数据库即可确定角色。
- 增强安全:JWT 使用签名和加密技术,使攻击更难以进行。
- 跨域支持:JWT 适合用于单点登录 (SSO)和跨域认证。它们允许用户在多个域或服务之间使用相同的令牌进行认证。
- 适应移动端:JWT 非常适合需要无状态认证的移动应用。令牌可以存储在客户端并随每个请求发送,提高效率和易用性。
JWT 认证的劣势
-
JWT 不能实时更新
一旦 JWT 签署,它不能被撤销或更新,并且将被视为有效,只要签名有效且未过期。
如果用户的访问权限更改(通常是降级),用户将仍然具有访问已移除资源的权限,直到 JWT 过期。同样,如果 JWT 包含基于角色的授权信息,新的授权范围将在旧的 JWT 过期之前不会生效。换句话说,JWT 不适合实时撤销,用户可以设置适当的过期时间来减轻这一问题。
-
多设备和撤销难题
在 JWT 过期之前无法验证所有已发出的 JWT,以使用户撤销所有设备。虽然理论上可以撤销签名密钥使 JWT 失效,但这也会使所有使用该密钥的 JWT 失效,处理缓存密钥的过程会使这种方法对于简单的用户撤销操作不太实际。
一些身份提供者可能有这些 JWT 问题的预构解决方案。有关更多信息,请查看"改善 JWT 认证体验的最佳实践”
JWT 和会话有什么区别?
会话和 JWT 是在无状态的 HTTP 世界中持久化认证和授权上下文的两种流行方法。虽然两种方法都有自己的优缺点,但它们提供了不同的优势和缺陷。
会话提供了对单个请求授权的更强保证,并且易于安全实现。然而,它们对服务器侧数据库验证的依赖引入了延迟开销,这可能会对高响应性应用的用户体验产生负面影响。
另一方面,JWT 有利于更快的授权和与外部应用的互操作性,但需要更多开发人员的努力来解决安全复杂性。例如,我们可以使用 webhook 来通知客户端用户的访问被撤销,以便客户端可以清除缓存的 JWT 并强制用户重新认证。
由于基于令牌的认证更适合扩展并且其缺点仍然可控,它越来越多地被现代应用采用。
会话 vs. JWT:选择合适的方法
你的认证方法应匹配你的应用的架构和具体需求。以下是一个快速指南以帮助你决定:
何时使用基于会话的认证
基于会话的认证最适用于需要实时会话控制、集中管理或可扩展性不是主要关注点的场合。以下是它适用的场景:
-
持久会话的 Web 应用
对于如在线购物网站,会话是跟踪用户,购物车和偏好设置所必需的。
-
需要实时会话控制的应用
银行或金融服务等应用得益于服务器控制的会话数据,确保健壮的访问管理和安全性。
-
单服务器或小规模系统
没有高可扩展性需求的内部工具或小规模应用依赖于简单的会话管理以获得易用性和可靠性。
何时使用 JWT 认证
JWT 认证更适用于优先考虑可扩展性、效率和分布式系统的应用。它特别适用于客户端和服务器之间的无状态交互。考虑为以下场合使用基于令牌的认证:
-
单点登录 (SSO)
JWT 非常适合 单点登录,允许用户只需认证一次,即可无缝访问多个服务或应用。分享关于使用 OAuth 2.0 和 OIDC 保护基于云的应用程序的详细解释,使用 JWT 格式作为访问令牌和 ID 令牌。
-
移动应用
移动应用通常偏向于使用 JWT 进行认证,因为令牌可安全地存储在设备上,并随每个 API 请求发送。探索适用于 Android / iOS 快速集成 JWT 认证。
-
微服务架构
在微服务环境中,JWT 允许每个服务独立验证令牌而不依赖于中心化的会话存储,确保可扩展性和效率。
-
跨域认证
JWT 在涉及多个域或子域(例如
api.example.com
,dashboard.example.com
和docs.example.com
)的情况下表现出色。与 cookies 不同,JWT 允许跨域认证而无需额外的依赖。 -
API 和 Web 服务
RESTful API 和 Web 服务通常使用 JWT 进行认证,因为它们轻量级、便携且消除了服务器端会话管理的需求。了解更多关于机器对机器认证用于应用直接与资源通信的场合。
改善 JWT 认证体验的最佳实践
JWT 认证是一个强大的工具,但可能伴随着一些影响用户体验的挑战。Logto 提供了一个轻松且可靠的解决方案来克服这些障碍,使其成为安全高效认证的首选。
使用 JWT 处理用户注销问题
JWT 认证的一个常见问题是确保适当的用户注销体验。Logto 用其现成的 SDK 简化了这一过程。
- 通过在客户端清除令牌和本地会话并重定向用户到 Logto 的终止会话端点,你可以轻松终止在客户端应用和服务器上的会话。
- 另外,Logto 支持后通道注销,使 AuthServer 能够在用户注销时通知所有共享同一会话的客户端应用。
这确保了你的生态系统中一致且安全的会话管理。了解更多关于注销机制及如何实现注销。
处理用户权限更改
使用 JWT 管理用户权限的实时更改可能也很棘手。由于 JWT 本质上是无状态的,任何更新的权限或角色可能要到令牌过期后才能生效。Logto 提供了有效处理这一问题的策略:
- **为该用户减少权限:**使用短的访问令牌过期时间,或通过 API 调用动态验证权限。
- **为该用户添加新权限:**更新 AuthServer 以包括新的权限范围,并重新向用户请求同意以应用这些更改。
这些解决方案有助于保持权限的更新并确保一个更安全、更响应的系统。了解更多关于管理用户权限变化的实时更改。