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

Spring Security OAuth2 Boot资源服务器提取JWT声明及转换器注入问题

解决Spring Boot资源服务器自定义JWT声明提取的问题

嘿,我刚好碰到过类似的场景,这就教你怎么把自定义的CustomAccessTokenConverter配置进去,让你能拿到JWT里的所有声明!

第一步:修改资源服务器配置类,注入并关联自定义转换器

你需要在SecurityConfiguration里配置令牌服务,把自定义转换器关联进去。根据你使用的令牌类型(JWT本地验证/引用令牌远程校验),有两种配置方式:

方式1:JWT令牌本地验证(推荐,无需每次调用授权服务器)

这种方式下,资源服务器直接本地验证JWT签名并解析声明:

@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends ResourceServerConfigurerAdapter {
    private final String resourceId;
    private final CustomAccessTokenConverter customAccessTokenConverter;

    @Autowired
    public SecurityConfiguration(@Value("${security.oauth2.resource.id}") String resourceId,
                                 CustomAccessTokenConverter customAccessTokenConverter) {
        this.resourceId = resourceId;
        this.customAccessTokenConverter = customAccessTokenConverter;
    }

    // 配置JWT转换器,关联自定义的声明提取逻辑
    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        // 如果你用的是非对称加密,从Identity Server获取公钥(推荐)
        converter.setVerifierKey(getIdentityServerPublicKey());
        // 如果你用的是对称加密,直接设置签名密钥
        // converter.setSigningKey("your-shared-secret-key");
        
        // 绑定自定义的AccessTokenConverter
        converter.setAccessTokenConverter(customAccessTokenConverter);
        return converter;
    }

    // 配置JWT令牌存储
    @Bean
    public TokenStore tokenStore() {
        return new JwtTokenStore(jwtAccessTokenConverter());
    }

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) {
        resources.resourceId(this.resourceId)
                 .tokenStore(tokenStore()); // 关联令牌存储,启用自定义转换器
    }

    @Override
    public void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity
                .csrf()
                .disable()
                .authorizeRequests()
                .antMatchers("/swagger-ui.html", "/webjars/**", "/swagger-resources/**", "/**/api-docs/**", "/actuator/**")
                .permitAll()
                .anyRequest().fullyAuthenticated();
    }

    // 辅助方法:从Identity Server获取公钥(示例)
    private String getIdentityServerPublicKey() {
        // 你可以从Identity Server的JWKS端点获取,比如 http://your-idsrv-url/.well-known/openid-configuration/jwks
        // 这里简化处理,实际可以用RestTemplate请求并解析
        return "-----BEGIN PUBLIC KEY-----\n你的公钥内容\n-----END PUBLIC KEY-----";
    }
}

方式2:引用令牌远程校验(适用于Identity Server下发的引用令牌)

如果你的授权服务器下发的是引用令牌(需要资源服务器调用授权服务器校验令牌有效性),则配置RemoteTokenServices:

@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends ResourceServerConfigurerAdapter {
    private final String resourceId;
    private final CustomAccessTokenConverter customAccessTokenConverter;

    @Autowired
    public SecurityConfiguration(@Value("${security.oauth2.resource.id}") String resourceId,
                                 CustomAccessTokenConverter customAccessTokenConverter) {
        this.resourceId = resourceId;
        this.customAccessTokenConverter = customAccessTokenConverter;
    }

    // 配置远程令牌校验服务
    @Bean
    public RemoteTokenServices remoteTokenServices() {
        RemoteTokenServices tokenServices = new RemoteTokenServices();
        // Identity Server的校验令牌端点
        tokenServices.setCheckTokenEndpointUrl("http://your-idsrv-url/connect/checktoken");
        // 资源服务器在Identity Server注册的客户端ID和密钥
        tokenServices.setClientId("your-resource-client-id");
        tokenServices.setClientSecret("your-resource-client-secret");
        // 绑定自定义转换器
        tokenServices.setAccessTokenConverter(customAccessTokenConverter);
        return tokenServices;
    }

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) {
        resources.resourceId(this.resourceId)
                 .tokenServices(remoteTokenServices()); // 关联远程令牌服务
    }

    @Override
    public void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity
                .csrf()
                .disable()
                .authorizeRequests()
                .antMatchers("/swagger-ui.html", "/webjars/**", "/swagger-resources/**", "/**/api-docs/**", "/actuator/**")
                .permitAll()
                .anyRequest().fullyAuthenticated();
    }
}

第二步:在控制器中获取声明信息

配置完成后,你就可以在控制器里通过OAuth2Authentication对象拿到所有声明了:

@RestController
@RequestMapping("/api")
public class UserController {

    // 方式1:通过@AuthenticationPrincipal注入
    @GetMapping("/profile")
    public Map<String, Object> getUserProfile(@AuthenticationPrincipal OAuth2Authentication authentication) {
        // 你的自定义转换器把所有声明存在了details里
        return (Map<String, Object>) authentication.getDetails();
    }

    // 方式2:从SecurityContextHolder获取
    @GetMapping("/claims")
    public Map<String, Object> getAllClaims() {
        OAuth2Authentication auth = (OAuth2Authentication) SecurityContextHolder.getContext().getAuthentication();
        return (Map<String, Object>) auth.getDetails();
    }
}

补充:配置文件参数

记得在application.properties或application.yml里补充必要的配置:

# 资源ID(要和Identity Server里配置的一致)
security.oauth2.resource.id=your-resource-id

# 如果用JWT本地验证,配置公钥获取地址(推荐)
security.oauth2.resource.jwt.key-uri=http://your-idsrv-url/.well-known/openid-configuration/jwks

这样配置后,你的自定义转换器就会生效,控制器里就能拿到JWT里的所有声明啦!

内容的提问来源于stack exchange,提问作者Daniel José Martínez Parra

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:43:54