对于最新的稳定版本,请使用 Spring Security 6.5.3! |
OAuth 2.0 资源服务器多租户
多租户
当有多种策略用于验证持有者Tokens(由某些租户标识符键)时,资源服务器被视为多租户。
例如,资源服务器可以接受来自两个不同授权服务器的持有者Tokens。 或者,授权服务器可以表示多个颁发者。
在每种情况下,都需要做两件事,并且权衡与您选择的执行方式相关:
-
解决租户问题。
-
传播租户。
通过索赔解决租户问题
区分租户的一种方法是通过发行人索赔。由于颁发者声明伴随着已签名的 JWT,因此您可以使用JwtIssuerReactiveAuthenticationManagerResolver
:
-
Java
-
Kotlin
JwtIssuerReactiveAuthenticationManagerResolver authenticationManagerResolver = new JwtIssuerReactiveAuthenticationManagerResolver
("https://idp.example.org/issuerOne", "https://idp.example.org/issuerTwo");
http
.authorizeExchange(exchanges -> exchanges
.anyExchange().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2
.authenticationManagerResolver(authenticationManagerResolver)
);
val customAuthenticationManagerResolver = JwtIssuerReactiveAuthenticationManagerResolver("https://idp.example.org/issuerOne", "https://idp.example.org/issuerTwo")
return http {
authorizeExchange {
authorize(anyExchange, authenticated)
}
oauth2ResourceServer {
authenticationManagerResolver = customAuthenticationManagerResolver
}
}
这很好,因为颁发者端点是延迟加载的。
事实上,相应的JwtReactiveAuthenticationManager
仅在发送具有相应颁发者的第一个请求时实例化。
这允许独立于那些已启动且可用的授权服务器的应用程序启动。
动态租户
您可能不希望在每次添加新租户时重新启动应用程序。
在这种情况下,您可以配置JwtIssuerReactiveAuthenticationManagerResolver
存储库为ReactiveAuthenticationManager
实例,您可以在运行时编辑这些实例:
-
Java
-
Kotlin
private Mono<ReactiveAuthenticationManager> addManager(
Map<String, ReactiveAuthenticationManager> authenticationManagers, String issuer) {
return Mono.fromCallable(() -> ReactiveJwtDecoders.fromIssuerLocation(issuer))
.subscribeOn(Schedulers.boundedElastic())
.map(JwtReactiveAuthenticationManager::new)
.doOnNext(authenticationManager -> authenticationManagers.put(issuer, authenticationManager));
}
// ...
JwtIssuerReactiveAuthenticationManagerResolver authenticationManagerResolver =
new JwtIssuerReactiveAuthenticationManagerResolver(authenticationManagers::get);
http
.authorizeExchange(exchanges -> exchanges
.anyExchange().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2
.authenticationManagerResolver(authenticationManagerResolver)
);
private fun addManager(
authenticationManagers: MutableMap<String, ReactiveAuthenticationManager>, issuer: String): Mono<JwtReactiveAuthenticationManager> {
return Mono.fromCallable { ReactiveJwtDecoders.fromIssuerLocation(issuer) }
.subscribeOn(Schedulers.boundedElastic())
.map { jwtDecoder: ReactiveJwtDecoder -> JwtReactiveAuthenticationManager(jwtDecoder) }
.doOnNext { authenticationManager: JwtReactiveAuthenticationManager -> authenticationManagers[issuer] = authenticationManager }
}
// ...
var customAuthenticationManagerResolver = JwtIssuerReactiveAuthenticationManagerResolver(authenticationManagers::get)
return http {
authorizeExchange {
authorize(anyExchange, authenticated)
}
oauth2ResourceServer {
authenticationManagerResolver = customAuthenticationManagerResolver
}
}
在本例中,您构造JwtIssuerReactiveAuthenticationManagerResolver
具有获取ReactiveAuthenticationManager
给予发行人。
这种方法允许我们在存储库中添加和删除元素(显示为Map
在前面的代码段中)运行时。
简单地采用任何发行人并构建一个 |