使用 Spring 和 JWT 进行基于令牌的身份验证

Posted

技术标签:

【中文标题】使用 Spring 和 JWT 进行基于令牌的身份验证【英文标题】:Token based authentication with Spring and JWT 【发布时间】:2020-04-13 20:40:33 【问题描述】:

我正在使用 Spring Security 和 JWT 为我的移动应用程序实现身份验证/授权系统,我对系统的实际设计有一些疑问。 这是允许用户访问安全 REST API 的身份验证/授权流程:

    移动应用程序向 /auth/token 端点发送一个请求,以及使用 basic 身份验证方案的用户的用户名和密码。 服务器对返回 JWT 访问和刷新令牌的用户进行身份验证。

    对端点 /api/** 表示的受保护资源的所有后续请求都是通过访问令牌执行的,该令牌由服务器验证和信任。验证和信任令牌的逻辑由在 spring 的 BasicAuthenticationFilter 之前执行的令牌过滤器执行。

    如果令牌不再有效,则客户端将刷新令牌 (JWT) 发送到 /auth/refresh 端点,该端点会验证此令牌,如果可信则返回一个新的访问令牌。 /auth/refresh 端点是公开的,但它依赖于 JWT 签名必须有效且受信任的事实。

我也在考虑使用 OAuth,但我想知道这种架构设计是否可以使用,或者它是否存在漏洞或可扩展性问题。 我对身份验证系统还很陌生,我正在尝试了解无需使用 OAuth 即可实施的正确方法。

【问题讨论】:

【参考方案1】:

您所描述的内容与 oauth 的密码流程基本相同,只是缺少 clientid 和 secret。 永远不要将访问令牌,尤其是刷新令牌转发给实际的应用程序,无论是应用程序还是 Web 应用程序。

始终考虑前后渠道。前端通道是您的应用程序运行的地方。不受信任的环境,例如手机、客户端渲染的应用程序等。

这些环境可能会受到影响。 因此,您的访问令牌应始终保存在服务器端。

但是:对于所描述的用例,您不一定需要 jwt。 如果您只需要登录,那么只使用启用了 csrf 验证检查的会话登录机制会更安全。

但是,如果您想使用 JWT,我建议您使用 OAUTH 的代码流或确保您的访问令牌存储在受信任的服务器端。

例如:

    如果用户登录,他会得到一个会话 cookie 作为回报。 之后,他还可以为特殊客户端(在本例中为您的资源服务器或 zuul 代理)和“read_profile、make_payments”等范围获取此类称为 authCode。 此 authCode 现在已发送到您的资源服务器或(位于端点前面的 zuul 代理) 资源服务器本身拥有自己的客户端凭据,现在通过身份验证服务器进行身份验证并获取访问令牌以换取身份验证码。

在任何情况下,您的用户都将基于双方的会话进行身份验证,并且您的资源服务器持有该用户的访问令牌。

【讨论】:

感谢克里斯的回复。令牌的目的不应该是无状态的,尤其是像 JWT 这样的签名令牌,因此不应该存储在服务器端吗?还因为我的访问令牌有 10 分钟的到期时间。我还考虑将刷新令牌存储在数据库中,以便在发生泄漏时撤销它们 如果你希望它是无状态的,你必须保存访问令牌客户端。仅在您拥有受信任的环境时才建议这样做。但是,无状态登录的目的是可扩展性和来自 authservice 的封装。使您能够代表用户授权第三方访问您的资源。 JWT 安全地存储在会话或数据库中。如果您水平扩展它,它将在您的实例之间共享,而无需再次调用身份验证服务。 始终认为,谁拥有你的访问令牌(refreshtoken),谁就可以完全访问你的资源。前端通道中的访问令牌是非常脆弱的东西。 顺便说一句。堆栈溢出的行为相同:-) 您已通过 JWT 登录。 accesstoken 和 refreshtokens 由 *** 存储,基于会话。 你也可以看看这个,尤其是对于移动应用程序?...developer.okta.com/blog/2019/08/22/okta-authjs-pkce

以上是关于使用 Spring 和 JWT 进行基于令牌的身份验证的主要内容,如果未能解决你的问题,请参考以下文章

带有 JWT 令牌的 Spring Security 和 Websocket

使用 Angular 和 spring 进行 Jwt 身份验证

将 Spring websockets (sockJS + Stomp) 与基于令牌的身份验证 (JWT) 一起使用的最佳方法

使用 Jwt 的基于令牌的身份验证无法授权

向 Google 进行身份验证时,从 Spring OAuth2 授权服务器发出 JWT 令牌

在 Spring Boot 中使用 JWT 进行简单的身份验证