OAuth 2.0 资源服务器多租户
多租户
当存在多种验证 Bearer 令牌的策略,并由某个租户标识符作为键时,资源服务器被认为是多租户的。
例如,您的资源服务器可以接受来自两个不同授权服务器的 Bearer 令牌。或者,您的授权服务器可以表示多个颁发者。
在每种情况下,都需要完成两件事,并且与您选择如何完成它们的方式相关联的是权衡取舍
-
解析租户。
-
传播租户。
通过声明解析租户
区分租户的一种方法是通过颁发者声明。由于颁发者声明附带已签名的 JWT,因此您可以使用 JwtIssuerReactiveAuthenticationManagerResolver
来实现。
-
Java
-
Kotlin
JwtIssuerReactiveAuthenticationManagerResolver authenticationManagerResolver = JwtIssuerReactiveAuthenticationManagerResolver
.fromTrustedIssuers("https://idp.example.org/issuerOne", "https://idp.example.org/issuerTwo");
http
.authorizeExchange(exchanges -> exchanges
.anyExchange().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2
.authenticationManagerResolver(authenticationManagerResolver)
);
val customAuthenticationManagerResolver = JwtIssuerReactiveAuthenticationManagerResolver
.fromTrustedIssuers("https://idp.example.org/issuerOne", "https://idp.example.org/issuerTwo")
return http {
authorizeExchange {
authorize(anyExchange, authenticated)
}
oauth2ResourceServer {
authenticationManagerResolver = customAuthenticationManagerResolver
}
}
这很好,因为颁发者端点是延迟加载的。事实上,只有当发送第一个具有相应颁发者的请求时,才会实例化相应的 JwtReactiveAuthenticationManager
。这允许应用程序启动独立于这些授权服务器的启动和可用性。
动态租户
您可能不希望每次添加新租户时都重新启动应用程序。在这种情况下,您可以使用 ReactiveAuthenticationManager
实例的存储库配置 JwtIssuerReactiveAuthenticationManagerResolver
,您可以在运行时编辑该存储库。
-
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
)添加和删除元素。
简单地获取任何颁发者并从中构造 |