Spring Security OAuth2实战指南:从零搭建企业级授权中心(附完整案例)
目录导读
- OAuth2核心概念与授权流程回顾
- 项目环境准备与技术选型
- 案例实战:构建授权服务器(Authorization Server)
- 案例实战:构建资源服务器(Resource Server)
- 案例实战:客户端(Client)接入与令牌刷新
- 常见问题问答(FAQ)
- 最佳实践与安全加固建议
OAuth2核心概念与授权流程回顾
在深入Spring Security OAuth2案例之前,我们必须理清OAuth2协议的四个关键角色:资源所有者(用户)、客户端(第三方应用)、授权服务器和资源服务器,最常用的授权模式是授权码模式(Authorization Code),它适用于有后端的Web应用。

其核心流程为:
- 用户访问客户端,客户端将用户重定向到授权服务器。
- 用户登录并同意授权。
- 授权服务器返回授权码(code)给客户端。
- 客户端用授权码换取访问令牌(Access Token)和刷新令牌(Refresh Token)。
- 客户端携带Access Token访问资源服务器。
案例核心:我们将用Spring Boot 2.7.x + Spring Security OAuth2实现一个完整的授权码模式,并解决JWT令牌的配置与自定义用户信息扩展问题。
项目环境准备与技术选型
我们采用以下技术栈构建案例:
- JDK 1.8+
- Spring Boot 2.7.18(注意:Spring Boot 2.7是集成Spring Security OAuth2的稳定版本,3.x已改用OAuth2 Client/Resource Server分离)
- Spring Security OAuth2 Autoconfigure(旧版依赖,但仍广泛用于企业存量项目)
- JWT(JSON Web Token)作为令牌格式
- Maven 构建工具
- MySQL + Spring Data JPA (用于存储客户端详情)
Maven关键依赖(pom.xml):
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.3.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-jwt</artifactId>
<version>1.1.1.RELEASE</version>
</dependency>
案例实战:构建授权服务器(Authorization Server)
步骤1:配置授权服务器核心类
创建AuthorizationServerConfig,继承AuthorizationServerConfigurerAdapter并重写三个核心configure方法。
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private DataSource dataSource;
@Autowired
private AuthenticationManager authenticationManager;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.jdbc(dataSource)
.withClient("client-app")
.secret(passwordEncoder().encode("secret123"))
.redirectUris("http://localhost:8082/login/oauth2/code/custom")
.authorizedGrantTypes("authorization_code", "refresh_token")
.scopes("read", "write")
.accessTokenValiditySeconds(3600)
.refreshTokenValiditySeconds(86400);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints.authenticationManager(authenticationManager)
.tokenStore(tokenStore())
.accessTokenConverter(accessTokenConverter());
}
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey("test-secret-key-change-in-production");
return converter;
}
}
步骤2:配置Spring Security 认证管理器
定义WebSecurityConfig,允许登录页面和令牌端点访问,并对其他请求进行认证。
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("admin").password(passwordEncoder().encode("123456")).roles("USER");
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
案例实战:构建资源服务器(Resource Server)
创建一个独立Spring Boot服务(端口9090),用于校验Access Token并返回受保护资源。
配置类:
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/api/**").authenticated()
.anyRequest().permitAll();
}
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey("test-secret-key-change-in-production"); // 与授权服务器一致
return converter;
}
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
}
资源控制器:
@RestController
@RequestMapping("/api")
public class UserResourceController {
@GetMapping("/profile")
public Map<String, String> getProfile(OAuth2Authentication auth) {
Map<String, String> result = new HashMap<>();
result.put("username", auth.getName());
result.put("clientId", auth.getOAuth2Request().getClientId());
return result;
}
}
案例实战:客户端(Client)接入与令牌刷新
客户端应用(端口8082)使用Spring Security OAuth2 Client依赖,通过@EnableOAuth2Sso实现SSO登录。
application.yml关键配置:
server:
port: 8082
security:
oauth2:
client:
client-id: client-app
client-secret: secret123
access-token-uri: http://localhost:8080/oauth/token
user-authorization-uri: http://localhost:8080/oauth/authorize
resource:
user-info-uri: http://localhost:9090/api/profile
刷新令牌实现:在后端定时任务或拦截器中,使用RestTemplate调用授权服务器的/oauth/token端点,grant_type=refresh_token获取新令牌。
private String refreshAccessToken(String refreshToken) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
body.add("grant_type", "refresh_token");
body.add("refresh_token", refreshToken);
body.add("client_id", "client-app");
body.add("client_secret", "secret123");
HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(body, headers);
ResponseEntity<Map> response = restTemplate.postForEntity("http://localhost:8080/oauth/token", entity, Map.class);
return (String) response.getBody().get("access_token");
}
常见问题问答(FAQ)
Q1:为什么在Spring Boot 2.7之后官方废弃了@EnableAuthorizationServer?
答:官方将OAuth2授权服务器迁移至Spring Authorization Server项目(独立于Spring Security),新版推荐使用
OAuth2AuthorizationServerConfigurer,但存量企业项目中使用2.3.x依赖仍是主流,且维护稳定。
Q2:JWT令牌中如何自定义用户信息(例如ID、角色)?
答:在授权服务器中重写
JwtAccessTokenConverter的enhance方法,或自定义TokenEnhancer,示例:((DefaultOAuth2AccessToken) accessToken).getAdditionalInformation().put("userId", "12345")。
Q3:资源服务器如何校验JWT有效性,无需每次都请求授权服务器?
答:使用JWT时,资源服务器通过签名密钥(对称密钥或公钥)本地校验,对称密钥需保证两端一致;非对称时,资源服务器配置
JwtAccessTokenConverter的setVerifierKey为公钥即可。
Q4:如果刷新令牌失效了,客户端应如何处理?
答:最好实现“静默登录”兜底:当刷新令牌请求返回
invalid_grant错误时,清除本地会话并重新引导用户走授权码流程,切勿无限重试。
最佳实践与安全加固建议
- 令牌传输: 生产环境务必使用HTTPS,避免令牌在明文网络中传输。
- 客户端密钥:
client-secret不要硬编码在配置文件,建议使用环境变量或配置中心(如Nacos、Consul)。 - JWT签名密钥: 生产环境更换为RSA非对称加密,非对称密钥对分开管理,且定期轮换。
- 令牌存储: 如果使用Redis存储令牌,需将
TokenStore改为RedisTokenStore,便于集中管理黑名单。 - Scope权限细化: 避免使用通配符
all,按业务拆分read_user、write_order等细粒度权限。
本案例完整覆盖了Spring Security OAuth2的授权服务器、资源服务器、客户端三方角色,从配置到代码实战解决了核心流程,理解该案例后,您可轻松扩展到微服务架构下的单点登录、API网关鉴权等场景,OAuth2不是银弹,合理搭配JWT、刷新令牌和细粒度权限控制,才能构建安全而灵活的企业级授权体系。