我有一个客户端 (SPA)/服务器 (REST) 应用程序,我需要对客户端进行身份验证并使它们在资源服务器中保持登录状态。应用程序通常必须使用位于第三方授权服务器上的外部 OAuth2 服务。现在的问题是:refresh_token应该存储在哪里?我有两个想法。
我故意省略了refresh_token到期时的情况。
假设
- 始终返回有效令牌以响应对任何受保护资源的请求和登录请求。
- 与授权服务器的所有通信都必须通过资源服务器,因为需要client_id和client_secret。
第一种情况
- 服务器按令牌存储映射refresh_token,并将令牌发送到客户端并响应登录请求。
- 客户端使用令牌发出请求。
- 服务器检查令牌是否有效。如果没有,它使用与令牌关联的refresh_token来生成新令牌。现在,在一分钟(或任何配置的持续时间)内,旧令牌将映射到新令牌,新令牌将映射到refresh_token以处理使用旧令牌排队的请求。
- 客户端使用令牌发出请求。
- 服务器检查令牌是否有效。如果没有,它会检查令牌是否映射到新令牌。如果是这样,它的行为就像使用新令牌发送请求一样(请参阅步骤 3)。否则,它会发送 401。
第二种情况
- 服务器将令牌和refresh_token发送到客户端,以响应登录请求。
- 客户端使用令牌发出请求。
- 服务器检查令牌是否有效。如果不是,则响应 401。
- 如果客户端使用状态为 401 的响应,它会尝试刷新令牌并使用新令牌发出相同的请求。
我知道这两种解决方案都有其弱点。是否有适用于此问题的良好做法?
访问令牌和刷新令牌应保留在获取它们的位置,尤其是在后端不使用 HTTPS 的情况下。
没有自己的 REST 后端的 SPA 应使用 OAuth 隐式流来获取访问令牌。隐式流不支持刷新令牌。
具有服务器端后端的应用程序应使用授权代码流(您的情况)。授权代码由后端交换以访问和刷新令牌,并应保留在那里。REST 后端可以使用访问令牌访问第三方资源,并在必要时使用刷新令牌续订访问令牌。
第二种情况是最可行的。首先,授权服务器不必与资源服务器相同。只能使用刷新令牌从授权服务器获取新的访问令牌。但是授权服务器和资源服务器都可以在同一台服务器中实现。
第一种方案中的客户端如何取回新的访问令牌?它正在请求资源(步骤 3),并且不希望取回新令牌。
我会将刷新令牌存储在客户端的浏览器本地存储或其他东西中。这不是很高的安全性,但可能是你能做的最好的事情。