spring-security Spring Security 5 -如何使用对称签名密钥?

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

我使用旧的Spring授权服务器和资源服务器运行微服务(org.springframework.cloud:spring-cloud-starter-oauth2现在已弃用)。
对于我正在创建的新微服务,我需要使用较新版本的Spring Security 5资源服务器实现。
下面是来自我的授权服务器的代码。

@Configuration
public class AuthorizationServerConfig implements AuthorizationServerConfigurer {

  private final PasswordEncoder passwordEncoder;
  private final DataSource dataSource;
  private final AuthenticationManager authenticationManager;
  private final UserDetailsService userDetailsService;
  private final CustomAccessTokenConverter customAccessTokenConverter;

  @Value("${signing-key:123}")
  private String signingKey;

  public AuthorizationServerConfig(
      PasswordEncoder passwordEncoder,
      DataSource dataSource,
      AuthenticationManager authenticationManager,
      UserDetailsService userDetailsService,
      CustomAccessTokenConverter customAccessTokenConverter) {
    this.passwordEncoder = passwordEncoder;
    this.dataSource = dataSource;
    this.authenticationManager = authenticationManager;
    this.userDetailsService = userDetailsService;
    this.customAccessTokenConverter = customAccessTokenConverter;
  }

  @Bean
  public JwtAccessTokenConverter accessTokenConverter() {
    final JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
    jwtAccessTokenConverter.setAccessTokenConverter(customAccessTokenConverter);
    jwtAccessTokenConverter.setSigningKey(signingKey);
    return jwtAccessTokenConverter;
  }

  @Bean
  public TokenStore tokenStore() {
    return new JwtTokenStore(accessTokenConverter());
  }

  @Bean
  public ApprovalStore approvalStore() {
    return new JdbcApprovalStore(dataSource);
  }

  @Bean
  public AuthorizationCodeServices authorizationCodeServices() {
    return new JdbcAuthorizationCodeServices(dataSource);
  }

  @Bean
  @Primary
  public DefaultTokenServices tokenServices() {
    final DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
    defaultTokenServices.setTokenStore(tokenStore());
    defaultTokenServices.setSupportRefreshToken(true);
    return defaultTokenServices;
  }

  @Bean
  public TokenEnhancer tokenEnhancer() {
    return new CustomTokenEnhancer();
  }

  @Override
  public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
    security.checkTokenAccess("isAuthenticated()").tokenKeyAccess("permitAll()");
  }

  @Override
  public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
    clients.jdbc(dataSource).passwordEncoder(passwordEncoder);
  }

  @Override
  public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
    TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
    tokenEnhancerChain.setTokenEnhancers(Arrays.asList(tokenEnhancer(), accessTokenConverter()));
    endpoints.tokenStore(tokenStore());
    endpoints.approvalStore(approvalStore());
    endpoints.authorizationCodeServices(authorizationCodeServices());
    endpoints.authenticationManager(authenticationManager);
    endpoints.tokenEnhancer(tokenEnhancerChain);
    endpoints.userDetailsService(userDetailsService);
  }
}

如何在Spring Security 5中使用对称签名密钥解密JWT?
根据迁移指南https://github.com/spring-projects/spring-security/wiki/OAuth-2.0-Migration-Guide,我可以选择使用JWT+JWK或JWT+Key,但不确定使用什么,因为我的签名密钥只是一个字符串。

jm2pwxwz

jm2pwxwz1#

我曾经遇到过与上面提到的完全相同的问题,我有旧的Oaut 2授权服务,并将旧的资源服务迁移到Spring Security 5标准。
我从OAuth2迁移指南中选择了JWT + Key场景。
在application.yml文件中,我添加了相同的singleKey和其他配置,用于调试SecurityFilterChain,以便能够根据文档控制授权流:

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          key-value: zSigFffuyF5CjmLAxubSTVBt5OnfbnGPkFpvNpg2n/.....

logging:
  level:
    org:
      springframework:
        security: DEBUG

在我的配置类中,我通过@Value注解注入了singleKey:

@Value("${spring.security.oauth2.resourceserver.jwt.key-value}")
    private String key;

然后我公开了SecurityFIlterChain上的默认配置:

@Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests(authorize -> authorize.anyRequest().authenticated())
                .oauth2ResourceServer((oauth2) -> oauth2.jwt((jwt) -> jwt.decoder(jwtDecoder())));

        return http.build();
    }

并为自定义的JTWDecoder bean添加将我的singleKey转换为SecretKey对象:

@Bean
    public JwtDecoder jwtDecoder() {
        byte[] secretByte = key.getBytes();
        SecretKey secretKey = new SecretKeySpec(secretByte, 0, secretByte.length, "RSA");
        return NimbusJwtDecoder.withSecretKey(secretKey).build();
    }

已配置debbugig的日志:

o.s.security.web.FilterChainProxy.doFilterInternal - Securing GET /example_endpoint
o.s.s.w.c.SecurityContextPersistenceFilter.doFilter - Set SecurityContextHolder to empty SecurityContext
o.s.s.o.s.r.a.JwtAuthenticationProvider.authenticate - Authenticated token
o.s.s.o.s.r.w.BearerTokenAuthenticationFilter.doFilterInternal - Set SecurityContextHolder to JwtAuthenticationToken [Principal=org.springframework.security.oauth2.jwt.Jwt@29cc3dff, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=172.16.57.7, SessionId=null], Granted Authorities=[SCOPE_BOU]]
o.s.security.web.FilterChainProxy.doFilter - Secured GET /example_endpoint

就像在文档中一样:https://docs.spring.io/spring-security/reference/5.7.2/servlet/oauth2/resource-server/jwt.html#oauth2resourceserver-jwt-architecture

相关问题