我在我的系统中有一个要求,即在某些流中,我必须使用具有特定私有/公共密钥的JWT,而其他流必须使用具有其他密钥的另一个JWT。
我使用的是spring oauth2授权服务器1.0.0。
当我尝试设置两个键时,生成jwks端点是正常的,但是当我执行POST /oauth2/标记时,我得到了以下异常:
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();
}
2条答案
按热度按时间u3r8eeie1#
我不确定我是否完全理解the RFC-7517,但它似乎允许有几个键,没有特别的限制。
我很惊讶,因为从解码端来看,我希望从JWKS端点获取THE密钥,以便使用给定的算法解码JWT:轮流试几把钥匙,直到其中一把起作用,这将是相当低效的。
您是否考虑过运行多个授权服务器示例,每个示例都有一个特定的密钥?我想您的客户端应该知道要联系哪个授权服务器,但是资源服务器需要多租户(接受由多个发行者发行的身份)。您必须为此提供
JwtIssuerAuthenticationManagerResolver
bean:我已经围绕
spring-boot-starter-oauth2-resource-server
编写了thin wrappers,它支持这种场景,只需要从属性文件进行配置(上面的bean是自动提供的):第一个
bogh5gae2#
OAuth有一个内置的机制来管理多个密钥,称为密钥标识符(kid)。这为授权服务器提供了一种自动更新令牌签名密钥的方法,在这种情况下,新旧密钥都在使用,但使用较新的密钥颁发较新的令牌。
检查以下两项:
通常,授权服务器允许您配置不同的令牌颁发者,然后您可以将令牌颁发者关联到客户端。这应该不会对应用程序代码产生影响,因为JWKS机制和子程序应该会处理它。