繁体   English   中英

Spring Oauth2 授权服务器 - 如何使用多个 JWK 密钥

[英]Spring Oauth2 Authorization Server - How to use multiples JWK Keys

我在我的系统中有一个要求,在某些流程中我必须使用 JWT 和特定的私钥/公钥,而其他流程必须使用另一个 JWT 和其他密钥。

我正在使用 spring oauth2 授权服务器 1.0.0。

当我尝试设置两个密钥时,生成 jwks 端点可以正常工作,但是当我执行 POST /oauth2/token 时,出现以下异常:

org.springframework.security.oauth2.jwt.JwtEncodingException: An error occurred while attempting to encode the Jwt: Found multiple JWK signing keys for algorithm 'RS256'
    at org.springframework.security.oauth2.jwt.NimbusJwtEncoder.selectJwk(NimbusJwtEncoder.java:128) ~[spring-security-oauth2-jose-6.0.0.jar:6.0.0]
    at org.springframework.security.oauth2.jwt.NimbusJwtEncoder.encode(NimbusJwtEncoder.java:108) ~[spring-security-oauth2-jose-6.0.0.jar:6.0.0]
    at org.springframework.security.oauth2.server.authorization.token.JwtGenerator.generate(JwtGenerator.java:159) ~[spring-security-oauth2-authorization-server-1.0.0.jar:1.0.0]
    at org.springframework.security.oauth2.server.authorization.token.JwtGenerator.generate(JwtGenerator.java:58) ~[spring-security-oauth2-authorization-server-1.0.0.jar:1.0.0]
    at org.springframework.security.oauth2.server.authorization.token.DelegatingOAuth2TokenGenerator.generate(DelegatingOAuth2TokenGenerator.java:59) ~[spring-security-oauth2-authorization-server-1.0.0.jar:1.0.0]
    at org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientCredentialsAuthenticationProvider.authenticate(OAuth2ClientCredentialsAuthenticationProvider.java:125) ~[spring-security-oauth2-authorization-server-1.0.0.jar:1.0.0]
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:182) ~[spring-security-core-6.0.0.jar:6.0.0]
    at org.springframework.security.oauth2.server.authorization.web.OAuth2TokenEndpointFilter.doFilterInternal(OAuth2TokenEndpointFilter.java:167) ~[spring-security-oauth2-authorization-server-1.0.0.jar:1.0.0]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.0.2.jar:6.0.2]

我在同一个授权服务器中必须使用 JWK 密钥的概念可以吗?

我如何实现授权服务器在特定的客户端凭据中使用一个 JWK 密钥,并在另一个客户端凭据中请求另一个 JWK 密钥?

我的代码:

@EnableWebSecurity
@Configuration
@Slf4j
public class AuthSecurityConfig {

    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SecurityFilterChain defaultFilterChain(HttpSecurity http) throws Exception {
        OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
        return http.formLogin(Customizer.withDefaults()).build();
    }

    @Bean
    public SecurityFilterChain authFilterChain(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest().authenticated();
        return http.formLogin(Customizer.withDefaults()).build();
    }

    public RegisteredClientRepository registeredClientRepository(PasswordEncoder passwordEncoder
            ,JdbcTemplate jdbcTemplate
            ) {
        JdbcRegisteredClientRepository clientRepository = new JdbcRegisteredClientRepository(jdbcTemplate);

                return clientRepository;
    }

    @Bean
    public OAuth2AuthorizationService auth2AuthorizationService(JdbcOperations jdbcOperations,
                                                                RegisteredClientRepository registeredClientRepository) {
        return new JdbcOAuth2AuthorizationService(
                jdbcOperations,
                registeredClientRepository
        );
    }

    @Bean
    public OAuth2AuthorizationConsentService oAuth2AuthorizationConsentService(JdbcOperations jdbcOperations,
                                                                               RegisteredClientRepository registeredClientRepository) {
        return new JdbcOAuth2AuthorizationConsentService(
                jdbcOperations,
                registeredClientRepository
        );
    }

   @Bean
    public JWKSet jwkSet(AuthProperties authProperties) throws Exception {
        List<JWK> keys = new ArrayList<>();
        
        for (JksProperties jwk : authProperties.getJksList()) {
            keys.add(loadRsa(jwk));
        }
        
        return new JWKSet(keys);
    }

   @Bean
    public JWKSource<SecurityContext> jwkSource(JWKSet jwkSet) {
        
        return ((jwkSelector, securityContext) -> jwkSelector.select(jwkSet));
    }

    @Bean
    public JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
        return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
    }


    @Bean
    public AuthorizationServerSettings authorizationServerSettings() {
        return AuthorizationServerSettings.builder().build();
    }

我不确定我是否完全理解RFC-7517 ,但它似乎允许有多个密钥,没有特别限制。

我很惊讶,因为从解码方面来看,我希望从 JWKS 端点获取使用给定算法解码 JWT密钥:依次尝试多个密钥直到一个有效......

您是否考虑过运行多个授权服务器实例,每个实例都有一个特定的密钥? 我想您的客户会知道要联系哪个授权服务器,但资源服务器需要多租户(接受多个发行者颁发的身份)。 您必须为此提供JwtIssuerAuthenticationManagerResolver bean:

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

我已经围绕spring-boot-starter-oauth2-resource-server编写了薄包装器,它支持这种场景,仅从属性文件进行配置(上面的 bean 是自动提供的):

<dependency>
    <groupId>com.c4-soft.springaddons</groupId>
    <!-- replace "webmvc" with "weblux" if your app is reactive -->
    <!-- replace "jwt" with "introspecting" to use token introspection instead of JWT decoding -->
    <artifactId>spring-addons-webmvc-jwt-resource-server</artifactId>
    <!-- this version is to be used with spring-boot 3.0.0, use 5.x for spring-boot 2.6.x or before -->
    <version>6.0.7</version>
</dependency>
@Configuration
@EnableMethodSecurity
public static class WebSecurityConfig { }
com.c4-soft.springaddons.security.issuers[0].location=https://localhost:8443
com.c4-soft.springaddons.security.issuers[0].authorities.claims=groups,roles
com.c4-soft.springaddons.security.issuers[1].location=https://localhost:8444
com.c4-soft.springaddons.security.issuers[1].authorities.claims=groups,roles


com.c4-soft.springaddons.security.cors[0].path=/some-api

OAuth 有一个内置的机制来管理多个密钥,称为密钥标识符 (kid)。 这为授权服务器提供了一种自动更新令牌签名密钥的方法,其中旧密钥和新密钥都在使用中,但较新的令牌使用较新的密钥颁发。

检查这两件事:

  • JWKS 必须返回多个具有不同 kid 值的公共 JWK 条目

  • 当向客户端发出 JWT 时,它必须在其 JWT header 中包含一个孩子,该孩子映射到用于验证它的公钥

通常,授权服务器将使您能够配置不同的令牌颁发者,然后您可以将令牌颁发者关联到客户端。 这应该不会对应用程序代码产生影响,因为 JWKS 机制和孩子们应该会处理它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM