如何使 Spring Security OAuth2 与负载均衡器一起使用? [英] How can I make Spring Security OAuth2 work with load balancer?

查看:130
本文介绍了如何使 Spring Security OAuth2 与负载均衡器一起使用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们目前有 4 个 Spring 应用程序使用 Spring Security Oauth2 项目进行身份验证.这些应用程序是 REST API,供我工作的公司的其他内部应用程序使用.

We currently have 4 Spring applications that use Spring Security Oauth2 project for authentication. The applications are REST APIs that are consumed by other internal applications in the company I work for.

在开发和 QA 环境中一切正常,因为我们没有进行负载平衡,现在我们处于预生产阶段,我们正面临负载平衡器 (LB) 的问题.

Everything was working fine in the development and QA environments as we were not doing load balancing, now that we are in pre-production we are facing an issue with the load balancer (LB).

这是此问题的工作流程:

This is the workflow for this issue:

  1. 客户端发送对 oauth 令牌的请求
  2. LB 将请求重定向到 Box 1
  3. Box 1 进行身份验证并返回有效的不记名令牌
  4. 客户端接收令牌并将其存储以通过会话使用
  5. 客户端在 REST API 中发送对服务的请求,将先前检索到的令牌添加到标头中
  6. LB 将请求重定向到 Box 2
  7. Box 2 无法进行身份验证,因为它无法识别令牌并返回无效凭据响应

我们正在使用内存用户存储:

We are using an in memory user store:

<bean id="tokenStore" class="org.springframework.security.oauth2.provider.token.InMemoryTokenStore" />

有没有办法让不同的盒子共享同一个代币存储?我知道有一个 JdbcTokenStore 可用于将令牌持久化到数据库,但我更愿意避免持久化令牌,因为这些应用程序指向仅存储业务信息的旧数据库.

Is there a way to make different boxes to share the same token store? I know there is a JdbcTokenStore that can be used to persist tokens to the db, but I would prefer to avoid persisting tokens as these applications point to a legacy database that only stores business information.

推荐答案

我回答这个问题有点晚了,但也许这会帮助寻找类似答案的人.在负载均衡器上使用多个 oauth 服务器时,您需要注意两个主要事项:

I'm a bit late to this question, but maybe this will help someone searching for a similar answer. There are two major things you need to watch out for when using multiple oauth servers on a load balancer:

正如@chris-h 在他的回答中所提到的,您需要确保任何其他 oauth 服务器都可以读取(和信任)支持由任何 oauth 服务器发布的访问令牌的信息.您可以按照他的建议使用 JDBC 令牌存储,但这样做的缺点是,如果服务器 A 必须验证服务器 B 发出的访问令牌,则它始终必须访问数据库才能这样做.

As @chris-h alluded to in his answer, you need to ensure that the information backing an access token issued by any of the oauth servers can be read (and trusted) by any of the other oauth servers. You can use a JDBC token store as he suggested, but this has the disadvantage that if Server A has to validate an access token issued by Server B, it always has to hit the database to do so.

更好的解决方案 (IMO) 是使用 JWT 访问令牌,其中验证令牌所需的所有信息都在其中加密.只要所有 oauth 服务器使用相同的加密密钥,它们就可以读取彼此访问令牌中的数据,并相信数据是有效的,因为它是加密的.优点是不需要数据库调用来验证访问令牌.缺点是访问令牌一经发出就没有简单的方法使它无效.如果您想知道为什么需要刷新令牌,而您可以增加访问令牌本身的过期时间,这就是最大的原因.

A better solution (IMO) is to use JWT access tokens, where all the information needed to validate the token is encrypted within it. So long as all oauth servers use the same encryption key, they can read the data in each other's access tokens and trust that the data is valid since it is encrypted. The advantage is there are no database calls needed to validate an access token. The disadvantage is that there's no easy way to invalidate an access token once it's been issued. If you ever wondered why refresh tokens are needed when you could just increase the expire time of the access tokens themselves, this is the biggest reason.

要注意的第二件事是 Spring oauth 实现使用会话来跟踪用户在身份验证过程中的位置.如果您不小心,您可能会陷入无限循环"的场景.假设您有两个 oauth 服务器——服务器 A 和服务器 B:

The second thing to be aware of is that the Spring oauth implementation uses sessions to keep track of where the user is an the authentication process. If you aren't careful, you could wind up in an "endless loop" scenario. Suppose you have two oauth servers--Server A and Server B:

  1. 用户转到需要身份验证的网页或服务,因此被重定向到foo.com/oauth/authorize".负载平衡器将此请求发送到服务器 A.
  2. 由于服务器 A 没有任何会话信息来证明用户已经通过身份验证,因此它将用户重定向到 foo.com/oauth/login 上的登录页面.重定向通过负载均衡器返回,并且由于负载均衡器以循环"方式工作,这次它将请求发送到服务器 B.
  3. 用户登录成功,因此会写入会话信息以对此进行跟踪.只有服务器 B 知道此会话信息.
  4. 由于登录成功,用户被重定向回foo.com/oauth/authorize"以继续身份验证过程.重定向再次通过负载平衡器返回.由于负载均衡器以循环"方式工作,这次它将请求发送到服务器 A.但服务器 A 不知道服务器 B 上发生的成功登录.返回第 2 步!

这个问题的最佳(当前)解决方案可能是确保您的负载均衡器支持粘性会话"——也就是说,一旦它将特定用户发送到服务器 A 或服务器 B,它总是将该用户发送到同一台服务器一段时间.

Probably the best (current) solution to this problem is to ensure that your load balancer supports "sticky sessions"--that is, once it sends a particular user to Server A or Server B, it always sends that user to the same server for a while.

更好的解决方案可能是让 oauth 实现完全不使用会话.相反,使用作为参数传递给/oauth/* 的加密数据表示您在登录过程中的位置.与 JWT 令牌的工作方式类似,如果所有服务器都共享加密密钥,则所有服务器都可以信任该信息.

A better solution might be for oauth implementations to not use sessions at all. Instead, use encrypted data passed as a parameter to /oauth/* that denotes where you are in the login process. Similar to how JWT tokens work, the information can be trusted by all servers if they all share the encryption key.

这篇关于如何使 Spring Security OAuth2 与负载均衡器一起使用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆