Spring Security OAuth2
Spring Security OAuth2 实现了 OAuth2 授权框架,支持多种授权模式,可构建授权服务器和资源服务器。
提示
OAuth2授权模式、授权码、社会化登录
授权模式
| 模式 | grant_type | 适用场景 |
|---|---|---|
| 授权码 | authorization_code | 第三方登录,最安全 |
| 密码 | password | 可信客户端 |
| 客户端凭证 | client_credentials | 服务间通信 |
| 刷新令牌 | refresh_token | token 续期 |
授权码模式流程
1. 客户端 → 授权服务器: /oauth/authorize?response_type=code&client_id=xxx
2. 用户登录授权
3. 授权服务器 → 客户端: redirect_uri?code=xxx
4. 客户端 → 授权服务器: POST /oauth/token (code, client_secret)
5. 授权服务器 → 客户端: {access_token, refresh_token}密码模式请求
POST /oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=password&username=user&password=pass&client_id=client&client_secret=secret资源服务器配置
Spring Boot 3.x + Spring Security 6.x:
@Configuration
@EnableWebSecurity
public class ResourceServerConfig {
@Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}")
private String issuerUri;
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/api/public/**").permitAll()
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2
.jwt(jwt -> jwt
.jwtAuthenticationConverter(jwtAuthenticationConverter())
)
);
return http.build();
}
private JwtAuthenticationConverter jwtAuthenticationConverter() {
JwtGrantedAuthoritiesConverter converter = new JwtGrantedAuthoritiesConverter();
converter.setAuthoritiesClaimName("roles");
converter.setAuthorityPrefix("ROLE_");
JwtAuthenticationConverter authConverter = new JwtAuthenticationConverter();
authConverter.setJwtGrantedAuthoritiesConverter(converter);
return authConverter;
}
}JWT 配置
spring:
security:
oauth2:
resourceserver:
jwt:
jwk-set-uri: https://auth.example.com/oauth2/default/v1/keys
issuer-uri: https://auth.example.com@Bean
public JwtDecoder jwtDecoder() {
return JwtDecoders.fromIssuerLocation(issuerUri);
}社会化登录
spring:
security:
oauth2:
client:
registration:
google:
client-id: ${GOOGLE_CLIENT_ID}
client-secret: ${GOOGLE_CLIENT_SECRET}
scope: [openid, profile, email]
github:
client-id: ${GITHUB_CLIENT_ID}
client-secret: ${GITHUB_CLIENT_SECRET}@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize -> authorize
.anyRequest().authenticated()
)
.oauth2Login(Customizer.withDefaults());
return http.build();
}权限控制
端点权限
http.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/contacts/**").access(hasScope("contacts"))
.requestMatchers("/messages/**").hasAuthority("SCOPE_messages")
.anyRequest().authenticated()
);方法级权限
@PreAuthorize("hasAuthority('SCOPE_messages')")
public List<Message> getMessages() {
return messageService.getMessages();
}OAuth2AuthorizedClient
@Bean
public OAuth2AuthorizedClientManager authorizedClientManager(
ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientRepository authorizedClientRepository) {
OAuth2AuthorizedClientProvider provider =
OAuth2AuthorizedClientProviderBuilder.builder()
.authorizationCode().refreshToken()
.clientCredentials().password().build();
DefaultOAuth2AuthorizedClientManager manager =
new DefaultOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository);
manager.setAuthorizedClientProvider(provider);
return manager;
}常见问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
| Token 验证失败 | 签名密钥不一致或 Token 过期 | 检查 JWT 签名密钥和 issuer-uri 配置 |
| 授权码获取失败 | client_id/redirect_uri 不匹配 | 确认客户端配置与授权服务器一致 |
| 权限不足 | JWT claims 或 Authority 前缀不匹配 | 检查 GrantedAuthority 转换器配置 |