Spring Security 无状态 OAuth2 授权代码授予流程

时间:2020-12-27 11:52:02

标签: spring-security oauth-2.0 openid-connect spring-security-oauth2 spring-oauth2

对于我的 Spring Boot 2.4 应用程序,我已经配置了在内部使用 OAuth 2.0 授权代码授予流程的 OAuth2 登录 (OpenID Connect)。

此流程的 OAuth 2.0 规范按照建议定义了 state 参数,主要用于 CSRF 保护问题。示例请求如下所示:

https://authorization-server.com/oauth/authorize
?client_id=a17c21ed
&response_type=code
&state=5ca75bd30
&redirect_uri=https%3A%2F%2Fexample-app.com%2Fauth
&scope=photos

由于应用程序应该与多个实例(至少两个)一起运行,我遇到了问题,因为此 state 参数是随机生成的,每个 Spring Boot 实例具有不同的值。因此回调必须到达发起请求的同一实例,否则,此 state 字段的验证将失败。

我找到的相关 Spring Security 代码部分如下(resolveDefaultOAuth2AuthorizationRequestResolver 方法)

builder.clientId(clientRegistration.getClientId())
                .authorizationUri(clientRegistration.getProviderDetails().getAuthorizationUri())
                .redirectUri(redirectUriStr)
                .scopes(clientRegistration.getScopes())
                .state(this.stateGenerator.generateKey()) // this line generates it
                .attributes(attributes);

如果我在负载均衡器上启用粘性会话,一切都会按预期进行。但是我不会将应用程序设置描述为完全无状态

有没有办法保留使用过的 state 参数,例如在一个数据库中在几个 Spring Boot 实例之间共享它以验证每个实例的回调?还是我必须手动提供自定义 StringKeyGenerator 并以某种方式调整 state 验证?

1 个答案:

答案 0 :(得分:2)

我查了一下,如你所说,好像是不可配置的,你的需求绝对不无道理。

我认为这值得在 Spring Security Github Issues 打开一个问题 stategenerator 至少应该是一个可以覆盖默认实现的接口,因为状态生成器不仅用作一种形式的CSRF,如果需要,它也应该可用于发送任何形式的自定义状态参数。

恐怕目前您拥有的解决方法是扩展默认 DefaultOAuth2AuthorizationRequestResolver 并覆盖 DefaultOAuth2AuthorizationRequestResolver#Resolve 函数并复制默认实现。

或者使用接口 OAuth2AuthorizationRequestResolver 实现自定义 OAuth2AuthorizationRequestResolver,并从默认代码中复制相关代码。

如果你有一个默认的实现,你可以自定义我会在服务之间实现一个共享的内存缓存,例如 Hazelcast 或 Redis,驱逐时间很短,这样你就不必处理数据库了。

>

但我确实认为您应该为他们打开一个问题以添加自定义。

我还发现 this 链接可以自定义一些内容。