Spring Security资源服务器取OAuth2Authentication的clientId为null、Jwt为空问题
核心问题原因
你的问题由两个配置和版本缺陷共同导致:
- 第一,资源服务器路径配置有误,你调用的
/token接口没有被纳入资源服务器的安全拦截范围,请求没有经过认证流程,因此上下文里的认证信息为空。 - 第二,你当前使用的Spring Security版本存在Keycloak JWT解析兼容缺陷,低于5.5.2版本的Spring Security OAuth资源服务器默认不会将JWT对象作为Principal注入,且
client_id字段提取逻辑存在bug。
修正方案
1. 调整路径匹配规则
你当前的配置只对/public/**路径生效,需要将所有需要保护的接口都添加到拦截规则中,示例如下:
@Configuration @EnableResourceServer @EnableGlobalMethodSecurity(prePostEnabled = true) public class ResourceServerSecurityConfig extends ResourceServerConfigurerAdapter { @Override public void configure(HttpSecurity http) throws Exception { http .authorizeRequests() // 所有需要保护的路径都在此处声明 .antMatchers("/public/**", "/token") .fullyAuthenticated() .and() .exceptionHandling() .accessDeniedHandler(accessDeniedHandler()) .authenticationEntryPoint(authenticationEntryPoint()); } @Bean RestAccessDeniedHandler accessDeniedHandler(){ return new RestAccessDeniedHandler(); } @Bean RestAuthenticationEntryPoint authenticationEntryPoint(){ return new RestAuthenticationEntryPoint(); } }
2. 低版本兼容配置
如果你暂时不想升级版本,可以自定义Token解析逻辑,将JWT信息和clientId注入到认证上下文中:
@Bean public JwtAccessTokenConverter accessTokenConverter() { JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); converter.setAccessTokenConverter(new DefaultAccessTokenConverter() { @Override public OAuth2Authentication extractAuthentication(Map<String, ?> claims) { OAuth2Authentication authentication = super.extractAuthentication(claims); // 将完整的JWT claims存入认证详情 authentication.setDetails(claims); return authentication; } }); // 填入你的JWT签名密钥或公钥 converter.setSigningKey("your-jwt-sign-key"); return converter; }
后续获取clientId时直接从认证详情中读取即可:
Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); Map<String, Object> claims = (Map<String, Object>) authentication.getDetails(); String clientId = (String) claims.get("client_id");
3. 长期最优方案
@EnableResourceServer是Spring Security OAuth项目中的废弃注解,该项目已经合并到Spring Security主项目中,建议使用Spring Security 5.x原生的OAuth2资源服务器实现,原生实现默认支持@AuthenticationPrincipal Jwt注入,也能正确解析Keycloak返回的所有JWT字段,不需要额外兼容配置。
内容的提问来源于stack exchange,提问作者Malvin Patrick
相关产品推荐
相关产品推荐

