You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 15:24:02