spring-security Spring安全性和OAuth2:是否可以将客户端注册添加到客户端注册存储库?

pepwfjgg  于 2022-11-11  发布在  Spring
关注(0)|答案(1)|浏览(161)

将Sping Boot 应用程序配置为使用单个OAuth2授权服务器是非常简单的。我的应用程序需要能够从多个事先未知的授权服务器获取身份验证令牌。我需要找到一种方法来动态管理它们。
从我所看到的,ClientRegistrationRepository在示例化时需要ClientRegistration。而AuthorizedClientServiceOAuth2AuthorizedClientManager需要ClientRegistrationRepositoryOAuth2AuthorizedClientService。我所看到的示例假设您将一次性配置ClientRegistration,并从那里开始构建客户端。我将需要能够添加和删除OAuth2身份验证服务器,但我事先不知道它们的详细信息。
spring-security对这个任务有用吗?我该如何组织使用动态oauth2服务器的工作?有没有更好的方法去做?

vql8enpb

vql8enpb1#

我迷惑不解:是否要添加具有客户端注册的授权服务器
多租户(多个授权服务器)是:

  • 如果所有访问令牌都是JWT,则更容易实现:您可以阅读iss声明,以了解使用哪个公钥来验证令牌签名(或者甚至向哪个服务器提交令牌以进行自检,但这是一种边缘情况)
  • 如果令牌是不透明的,则会变得复杂、肮脏和低效:您必须提供一个内省器,它将每个令牌提交给每个授权服务器,挑选唯一的肯定响应(如果有的话)。

此后的解决方案不是完全动态的(在属性中声明的多租户=〉需要重新启动以添加新的发布者),并且仅适用于JWT解码器。
我有支持JWT多租户的spring-boot启动库。示例there

com.c4-soft.springaddons.security.issuers[0].location=https://localhost:8443/realms/master
com.c4-soft.springaddons.security.issuers[1].location=https://bravo-ch4mp:8443/realms/master

# more properties per issuer for authorities mapping

您可以浏览source code以了解这是如何实现的:

http.oauth2ResourceServer(oauth2 -> oauth2.authenticationManagerResolver(authenticationManagerResolver));

@Bean
    JwtIssuerAuthenticationManagerResolver authenticationManagerResolver(
            OAuth2ResourceServerProperties auth2ResourceServerProperties,
            SpringAddonsSecurityProperties securityProperties,
            Converter<Jwt, ? extends AbstractAuthenticationToken> authenticationConverter) {
        final Optional<IssuerProperties> bootIssuer = Optional.ofNullable(auth2ResourceServerProperties.getJwt())
                .flatMap(jwt -> Optional
                        .ofNullable(StringUtils.hasLength(jwt.getIssuerUri()) ? jwt.getIssuerUri() : null))
                .map(issuerUri -> {
                    final IssuerProperties issuerProps = new IssuerProperties();
                    issuerProps.setJwkSetUri(
                            Optional.ofNullable(auth2ResourceServerProperties.getJwt().getJwkSetUri())
                                    .map(uri -> StringUtils.hasLength(uri) ? uri : null)
                                    .map(jwkSetUri -> {
                                        try {
                                            return new URI(jwkSetUri);
                                        } catch (URISyntaxException e) {
                                            throw new RuntimeException(
                                                    "Malformed JWK-set URI: %s".formatted(jwkSetUri));
                                        }
                                    }).orElse(null));
                    return issuerProps;
                });

        final Map<String, AuthenticationManager> jwtManagers = Stream
                .concat(bootIssuer.stream(), Stream.of(securityProperties.getIssuers()))
                .collect(Collectors.toMap(issuer -> issuer.getLocation().toString(), issuer -> {
                    final JwtDecoder decoder = issuer.getJwkSetUri() != null
                            && StringUtils.hasLength(issuer.getJwkSetUri().toString())
                                    ? NimbusJwtDecoder.withJwkSetUri(issuer.getJwkSetUri().toString()).build()
                                    : JwtDecoders.fromIssuerLocation(issuer.getLocation().toString());
                    final var provider = new JwtAuthenticationProvider(decoder);
                    provider.setJwtAuthenticationConverter(authenticationConverter::convert);
                    return provider::authenticate;
                }));

        log.debug(
                "Building default JwtIssuerAuthenticationManagerResolver with: ",
                auth2ResourceServerProperties.getJwt(),
                Stream.of(securityProperties.getIssuers()).toList());

        return new JwtIssuerAuthenticationManagerResolver((AuthenticationManagerResolver<String>) jwtManagers::get);
    }

相关问题