使用Keycloak作为授权服务器时资源服务器报错:enc(use)暂不支持
解决Spring Security资源服务器"enc (use) is currently not supported"错误
问题根源
Keycloak 15返回的JWK(JSON Web Key)集合中包含了**加密用途(use=enc)的密钥,但你当前使用的JwkTokenStore属于Spring Security OAuth2的旧实现,仅支持处理签名验证用途(use=sig)**的密钥,加载JWK时触发不支持的错误,导致请求在过滤器阶段就失败,无法进入控制器。
解决方案
推荐切换到Spring Security 5.x引入的OAuth2资源服务器新API(旧的@EnableResourceServer已进入维护模式),新API会自动处理不同用途的JWK,同时更适配现代OAuth2/JWT场景。
步骤1:替换资源服务器配置类
删除原有的ResourceServerConfig,改用以下基于SecurityFilterChain的配置:
@Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class ResourceServerConfig { @Value("${claim.aud}") private String claimAud; @Value("${jwkSetUri}") private String urlJwk; @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.authorizeRequests() .mvcMatchers(HttpMethod.DELETE, "/**").hasAuthority("fitnessadmin") .anyRequest().authenticated() .and() .oauth2ResourceServer(oauth2 -> oauth2 .jwt(jwt -> jwt .jwkSetUri(urlJwk) // 验证token的audience是否匹配资源ID .audienceValidator(audience -> audience.contains(claimAud)) // 自定义JWT到权限的转换(适配Keycloak的roles声明) .jwtAuthenticationConverter(jwtAuthenticationConverter()) ) ); return http.build(); } @Bean public JwtAuthenticationConverter jwtAuthenticationConverter() { JwtGrantedAuthoritiesConverter authoritiesConverter = new JwtGrantedAuthoritiesConverter(); // 指定Keycloak中存储角色的声明字段 authoritiesConverter.setAuthoritiesClaimName("roles"); // 去掉默认的"SCOPE_"前缀,因为你的角色是fitnessuser、fitnessadmin authoritiesConverter.setAuthorityPrefix(""); JwtAuthenticationConverter converter = new JwtAuthenticationConverter(); converter.setJwtGrantedAuthoritiesConverter(authoritiesConverter); return converter; } }
步骤2:确保依赖正确
如果你的项目使用Maven,确保引入了Spring Security OAuth2资源服务器的starter:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-oauth2-resource-server</artifactId> </dependency>
备选方案(兼容旧API)
如果暂时不想切换新API,可以自定义JWK过滤逻辑,只加载use=sig的密钥:
@Bean public TokenStore tokenStore() { JwkSetUriJwtAccessTokenConverter converter = new JwkSetUriJwtAccessTokenConverter(); converter.setJwkSetUri(urlJwk); // 自定义JWK转换器,过滤加密密钥 converter.setJwkConverter(jwkSet -> { List<JWK> filteredJwks = jwkSet.getKeys().stream() .filter(jwk -> "sig".equals(jwk.getUse())) .collect(Collectors.toList()); return new JWKSet(filteredJwks); }); return new JwtTokenStore(converter); }
验证修改
- 重启资源服务器
- 使用已获取的access token请求添加健身记录的接口
- 此时过滤器会正常处理JWT验证,请求能进入控制器,断点可以触发
内容的提问来源于stack exchange,提问作者Geralt
相关产品推荐
相关产品推荐

