如何配置Spring Authorization Server兼容旧版Spring Security OAuth2?
要同时实现旧令牌验证兼容和新令牌格式匹配旧系统,需要从资源服务器和授权服务器两部分配合配置:
一、资源服务器:兼容旧令牌验证
资源服务器需要沿用旧版OAuth2使用的签名密钥和JWT解析规则,确保旧令牌能正常通过验证。
1. 配置签名密钥
如果旧系统使用对称密钥(DefaultTokenServices常用HS256对称算法),直接指定该密钥:
@Bean public JwtDecoder jwtDecoder() { // 替换为旧系统实际使用的签名密钥 String oldSigningKey = "your-old-signing-key-string"; SecretKey secretKey = Keys.hmacShaKeyFor(oldSigningKey.getBytes(StandardCharsets.UTF_8)); return NimbusJwtDecoder.withSecretKey(secretKey).build(); }
如果旧系统用RSA非对称密钥,加载对应公钥即可:
@Bean public JwtDecoder jwtDecoder() throws Exception { Resource publicKeyResource = new ClassPathResource("old-public-key.pem"); RSAPublicKey publicKey = (RSAPublicKey) KeyFactory.getInstance("RSA") .generatePublic(new X509EncodedKeySpec(FileCopyUtils.copyToByteArray(publicKeyResource.getInputStream()))); return NimbusJwtDecoder.withPublicKey(publicKey).build(); }
2. 适配旧JWT声明(按需配置)
如果旧令牌的声明字段和Spring Security默认规则不一致(比如旧版用user_name而非sub、authorities而非scope),自定义转换器映射:
@Bean public JwtAuthenticationConverter jwtAuthenticationConverter() { JwtGrantedAuthoritiesConverter authoritiesConverter = new JwtGrantedAuthoritiesConverter(); authoritiesConverter.setAuthoritiesClaimName("authorities"); authoritiesConverter.setAuthorityPrefix("ROLE_"); JwtAuthenticationConverter converter = new JwtAuthenticationConverter(); converter.setJwtGrantedAuthoritiesConverter(authoritiesConverter); converter.setPrincipalClaimName("user_name"); return converter; }
在资源服务器安全链中应用该转换器:
@Bean public SecurityFilterChain resourceServerFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth.anyRequest().authenticated()) .oauth2ResourceServer(oauth2 -> oauth2 .jwt(jwt -> jwt .decoder(jwtDecoder()) .jwtAuthenticationConverter(jwtAuthenticationConverter()) ) ); return http.build(); }
二、授权服务器:生成兼容旧格式的新令牌
授权服务器需要配置令牌生成逻辑,确保新JWT的签名算法、密钥、声明字段与旧令牌完全一致。
1. 配置签名密钥与算法
沿用旧系统的签名密钥和算法:
@Bean public JWKSource<SecurityContext> jwkSource() { String oldSigningKey = "your-old-signing-key-string"; SecretKey secretKey = Keys.hmacShaKeyFor(oldSigningKey.getBytes(StandardCharsets.UTF_8)); JWKSet jwkSet = new JWKSet(new OctetSequenceKey.Builder(secretKey) .algorithm(JWSAlgorithm.HS256) .keyID("old-system-key-id") .build()); return new ImmutableJWKSet<>(jwkSet); }
2. 自定义JWT声明映射
确保新令牌包含旧系统依赖的所有声明字段:
@Bean public OAuth2TokenCustomizer<JwtEncodingContext> jwtTokenCustomizer() { return context -> { Authentication principal = context.getPrincipal(); if (principal instanceof UserDetails userDetails) { // 映射旧版用户名声明 context.getClaims().claim("user_name", userDetails.getUsername()); // 映射旧版权限声明 List<String> authorities = userDetails.getAuthorities().stream() .map(GrantedAuthority::getAuthority) .collect(Collectors.toList()); context.getClaims().claim("authorities", authorities); } // 保持issuer与旧系统一致 context.getClaims().issuer("http://your-old-auth-server-issuer-url"); }; }
3. 配置授权服务器令牌生成逻辑
在授权服务器安全链中指定令牌生成规则:
@Bean public SecurityFilterChain authorizationServerFilterChain(HttpSecurity http) throws Exception { OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http); http.getConfigurer(OAuth2AuthorizationServerConfigurer.class) .tokenGenerator(tokenGenerator(jwkSource(), jwtTokenCustomizer())); return http.build(); } @Bean public OAuth2TokenGenerator<?> tokenGenerator(JWKSource<SecurityContext> jwkSource, OAuth2TokenCustomizer<JwtEncodingContext> customizer) { JwtGenerator jwtGenerator = new JwtGenerator(jwkSource); jwtGenerator.setJwtCustomizer(customizer); return new DelegatingOAuth2TokenGenerator(jwtGenerator); }
关键注意事项
- 签名密钥必须和旧系统完全一致,包括字符编码,否则旧令牌会验证失败。
- 用jwt.io解析旧令牌,对比所有声明字段,确保新令牌的字段名称、格式完全匹配。
- 先在测试环境验证:用旧令牌访问资源服务器确认授权正常;用新授权服务器生成令牌,确认资源服务器能验证通过且业务逻辑不受影响。
内容的提问来源于stack exchange,提问作者Ken DeLong
相关产品推荐
相关产品推荐

