对于我的 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 代码部分如下(resolve
的 DefaultOAuth2AuthorizationRequestResolver
方法)
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
验证?
答案 0 :(得分:2)
我查了一下,如你所说,好像是不可配置的,你的需求绝对不无道理。
我认为这值得在 Spring Security Github Issues 打开一个问题 stategenerator 至少应该是一个可以覆盖默认实现的接口,因为状态生成器不仅用作一种形式的CSRF,如果需要,它也应该可用于发送任何形式的自定义状态参数。
恐怕目前您拥有的解决方法是扩展默认 DefaultOAuth2AuthorizationRequestResolver
并覆盖 DefaultOAuth2AuthorizationRequestResolver#Resolve
函数并复制默认实现。
或者使用接口 OAuth2AuthorizationRequestResolver
实现自定义 OAuth2AuthorizationRequestResolver
,并从默认代码中复制相关代码。
如果你有一个默认的实现,你可以自定义我会在服务之间实现一个共享的内存缓存,例如 Hazelcast 或 Redis,驱逐时间很短,这样你就不必处理数据库了。
>但我确实认为您应该为他们打开一个问题以添加自定义。
我还发现 this 链接可以自定义一些内容。