题目
设计高安全性的OAuth2授权服务器与资源服务器集成方案
信息
- 类型:问答
- 难度:⭐⭐⭐
考点
OAuth2授权服务器配置,自定义TokenEnhancer,JWT令牌验证,资源服务器安全策略,Spring Security过滤器链
快速回答
实现方案要点:
- 配置
@EnableAuthorizationServer并重写AuthorizationServerConfigurerAdapter - 实现
TokenEnhancer接口添加自定义声明到JWT - 资源服务器使用
@EnableResourceServer并配置JWT解码器 - 通过
SecurityConfig定义端点访问策略 - 使用
JwtTokenStore替代默认令牌存储
核心架构原理
Spring Security OAuth2架构分为授权服务器(负责颁发令牌)和资源服务器(验证令牌)。JWT作为无状态令牌包含元数据和声明,需解决三个关键问题:
- 授权服务器如何生成包含自定义数据的JWT
- 资源服务器如何验证JWT签名和有效期
- 如何统一安全策略保护端点
完整实现方案
1. 授权服务器配置(AuthorizationServerConfig)
@Configuration
@EnableAuthorizationServer
public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("clientapp")
.secret(passwordEncoder().encode("secret"))
.authorizedGrantTypes("password", "refresh_token")
.scopes("read", "write")
.accessTokenValiditySeconds(3600);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints
.authenticationManager(authenticationManager)
.tokenStore(tokenStore())
.tokenEnhancer(tokenEnhancerChain()); // 注入自定义增强器
}
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey("strongSecretKey123!"); // 生产环境使用非对称加密
return converter;
}
@Bean
public TokenEnhancer tokenEnhancer() {
return (accessToken, authentication) -> {
Map<String, Object> additionalInfo = new HashMap<>();
additionalInfo.put("organization", authentication.getName() + "_ORG");
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
return accessToken;
};
}
@Bean
public TokenEnhancerChain tokenEnhancerChain() {
TokenEnhancerChain chain = new TokenEnhancerChain();
chain.setTokenEnhancers(Arrays.asList(tokenEnhancer(), accessTokenConverter()));
return chain;
}
}2. 自定义TokenEnhancer关键逻辑
- 通过Lambda实现
TokenEnhancer接口 - 在
additionalInfo中添加业务字段(如组织信息) - 使用
TokenEnhancerChain确保自定义增强器在JWT转换前执行
3. 资源服务器配置(ResourceServerConfig)
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/api/public/**").permitAll()
.antMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated();
}
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey("strongSecretKey123!"); // 需与授权服务器一致
return converter;
}
}4. 安全全局配置(WebSecurityConfig)
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/oauth/token").permitAll()
.anyRequest().authenticated();
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}最佳实践与注意事项
| 实践要点 | 错误示例 | 正确方案 |
|---|---|---|
| 密钥管理 | 硬编码在代码中 | 使用环境变量或密钥管理服务(如HashiCorp Vault) |
| 令牌增强 | 添加敏感用户数据 | 仅添加必要业务标识(如user_id, org_code) |
| 签名算法 | HS256对称加密 | 生产环境使用RS256非对称加密 |
常见问题排查
- 令牌验证失败:检查资源服务器与授权服务器的签名密钥是否一致
- 自定义字段丢失:确保
TokenEnhancerChain顺序正确,自定义增强器需在JwtAccessTokenConverter之前 - 权限失效:在资源服务器配置中检查
hasRole()是否添加了ROLE_前缀
扩展知识
- JWT解码优化:使用
JwtDecoder自定义令牌解析逻辑 - 动态客户端注册:实现
ClientDetailsService对接数据库 - 令牌自省:通过
OpaqueTokenIntrospector处理不透明令牌 - 最新迁移方案:Spring Security 5.4+推荐使用
spring-security-oauth2-authorization-server替代废弃模块