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
相关产品推荐
相关产品推荐

