簡體   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