# OAuth2.0 资源服务器多租户
# 多重租赁
当存在多个用于验证由某个租户标识符控制的承载令牌的策略时,资源服务器被认为是多租户的。
例如,你的资源服务器可能接受来自两个不同授权服务器的承载令牌。或者,你的授权服务器可能表示多个发行者。
在每种情况下,都需要做两件事,以及与选择如何做这些事情相关的权衡:
解决租户
宣传租户
# 通过索赔来解决承租人的问题
区分租户的一种方法是通过签发人索赔。由于发行者声明伴随着已签名的 JWTS,因此可以使用JwtIssuerReactiveAuthenticationManagerResolver
来完成此操作,如下所示:
爪哇
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)
);
Kotlin
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
实例,你可以在运行时对其进行编辑,如下所示:
爪哇
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)
);
Kotlin
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
)。
简单地获取任何发行者并从中构造ReactiveAuthenticationManager 将是不安全的。发行者应该是代码可以从可信来源(如允许的发行者列表)验证的发行者。 |
---|