在 Spring Security 中集成 OAuth 2.0 可以实现安全的第三方认证和资源保护。以下是完整的配置指南和代码示例:
一、OAuth 2.0 核心概念
角色 | 作用 |
---|---|
资源所有者 | 用户(授权访问资源的人) |
客户端 | 应用(如Web、移动端) |
授权服务器 | 颁发访问令牌(如 Google、自建服务器) |
资源服务器 | 存储受保护资源,验证令牌后允许访问(如API服务) |
二、快速实现 OAuth 2.0 登录(第三方登录)
1. 添加依赖
<!-- Spring Security OAuth2 Client -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
2. 配置第三方 OAuth 2.0 客户端(以 Google 为例)
# application.yml
spring:
security:
oauth2:
client:
registration:
google:
client-id: your-google-client-id
client-secret: your-google-client-secret
scope: email, profile # 请求的权限范围
3. 启用 OAuth 2.0 登录
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated() // 所有请求需认证
.and()
.oauth2Login() // 启用 OAuth2 登录
.userInfoEndpoint()
.userService(customOAuth2UserService); // 自定义用户信息处理
return http.build();
}
@Autowired
private CustomOAuth2UserService customOAuth2UserService;
}
4. 自定义用户信息处理
@Service
public class CustomOAuth2UserService extends DefaultOAuth2UserService {
@Override
public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
OAuth2User user = super.loadUser(userRequest);
// 提取用户信息并转换为应用内的用户模型
return new CustomOAuth2User(user);
}
}
三、自建 OAuth 2.0 授权服务器
1. 添加依赖
<!-- 授权服务器支持 -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-authorization-server</artifactId>
<version>0.4.0</version> <!-- 检查最新版本 -->
</dependency>
2. 配置授权服务器
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private AuthenticationManager authenticationManager;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("client-id")
.secret(passwordEncoder.encode("client-secret"))
.authorizedGrantTypes("authorization_code", "refresh_token")
.scopes("read", "write")
.redirectUris("http://localhost:8080/login/oauth2/code/custom");
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints.authenticationManager(authenticationManager);
}
}
四、资源服务器配置(保护API)
1. 添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
2. 配置资源服务器
@Configuration
@EnableWebSecurity
public class ResourceServerConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/api/**").authenticated()
.and()
.oauth2ResourceServer()
.jwt(); // 使用 JWT 令牌验证
return http.build();
}
// JWT 解码配置
@Bean
public JwtDecoder jwtDecoder() {
return NimbusJwtDecoder.withJwkSetUri("http://auth-server/.well-known/jwks.json").build();
}
}
五、OAuth 2.0 授权模式
1. 授权码模式(最安全)
GET /oauth2/authorize?response_type=code&client_id=client-id&redirect_uri=http://client/callback&scope=read
2. 密码模式(仅信任客户端)
// 配置客户端支持密码模式
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("client-id")
.secret(passwordEncoder.encode("secret"))
.authorizedGrantTypes("password", "refresh_token")
.scopes("read");
}
六、JWT 令牌配置
1. 生成 JWT 令牌
@Bean
public JwtEncoder jwtEncoder() {
return new NimbusJwtEncoder(new ImmutableSecret<>(secretKey.getBytes()));
}
@Bean
public JwtGenerator jwtGenerator(JwtEncoder jwtEncoder) {
return new JwtGenerator(jwtEncoder);
}
2. 自定义令牌声明
public class CustomJwtTokenEnhancer implements JwtEncoder {
@Override
public Jwt encode(JwtEncoderParameters parameters) throws JwtEncodingException {
JwsHeader headers = JwsHeader.with(MACAlgorithm.HS256).build();
JwtClaimsSet claims = parameters.getClaims().build();
// 添加自定义声明
claims.claim("user_role", "ADMIN");
return new Jwt(headers, claims, "signature");
}
}
七、安全最佳实践
-
强制 HTTPS
生产环境必须启用 HTTPS,防止令牌泄露。http.requiresChannel().anyRequest().requiresSecure();
-
令牌存储安全
避免在客户端存储令牌,推荐使用HttpOnly
Cookie。 -
密钥管理
使用加密的密钥库(如 Vault)存储client-secret
和 JWT 签名密钥。 -
令牌有效期
设置短期的访问令牌和可刷新的长期令牌:.accessTokenValiditySeconds(3600) // 1小时 .refreshTokenValiditySeconds(2592000); // 30天
八、常见问题解决
1. 令牌无效或过期
• 检查项:
• 令牌签名是否正确
• 有效期是否过期
• 令牌是否被撤销
2. 跨域问题
确保授权服务器的 CORS 配置允许客户端域:
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedOrigins(Arrays.asList("http://client-domain"));
config.setAllowedMethods(Arrays.asList("GET", "POST"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return source;
}
总结
通过 Spring Security 集成 OAuth 2.0,您可以实现以下功能:
• 第三方登录(如 Google、GitHub)
• 安全的 API 保护(JWT 或 Opaque 令牌)
• 自建授权服务器(支持多客户端、多授权模式)
关键配置点:
• oauth2Client
配置第三方登录
• @EnableAuthorizationServer
创建授权服务器
• oauth2ResourceServer
保护资源
• 结合 JWT 实现无状态认证
遵循安全最佳实践,确保令牌安全和系统防护。