Spring Security OAuth2单点登录通过统一的授权服务器管理用户认证状态,多个客户端系统只需要对接授权服务器即可实现一次登录多处访问的效果,核心流程遵循OAuth2的授权码模式。

核心组件说明
实现整套单点登录需要三个核心角色:
- 授权服务器:负责用户身份认证,发放访问令牌和刷新令牌,是整个单点登录体系的核心
- 资源服务器:提供受保护的业务接口,需要校验令牌的合法性
- 客户端应用:需要接入单点登录的业务系统,引导用户跳转到授权服务器完成认证
授权服务器搭建
首先创建授权服务器项目,引入相关依赖:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.5.2.RELEASE</version>
</dependency>
</dependencies>
接着配置授权服务器核心类,继承AuthorizationServerConfigurerAdapter:
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
@Configuration
@EnableAuthorizationServer
public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// 配置客户端信息,实际项目可对接数据库存储
clients.inMemory()
.withClient("client1") // 客户端ID
.secret("{noop}secret1") // 客户端密钥,{noop}表示不加密
.redirectUris("http://127.0.0.1:8081/login/oauth2/code/custom") // 客户端回调地址
.scopes("read", "write") // 授权范围
.authorizedGrantTypes("authorization_code", "refresh_token") // 授权类型
.and()
.withClient("client2")
.secret("{noop}secret2")
.redirectUris("http://127.0.0.1:8082/login/oauth2/code/custom")
.scopes("read")
.authorizedGrantTypes("authorization_code", "refresh_token");
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) {
// 允许表单认证,方便测试
security.allowFormAuthenticationForClients();
}
}
然后配置Spring Security用户认证,继承WebSecurityConfigurerAdapter:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// 配置内存用户,实际项目可对接数据库或LDAP
auth.inMemoryAuthentication()
.withUser("user1")
.password(passwordEncoder().encode("123456"))
.roles("USER")
.and()
.withUser("admin")
.password(passwordEncoder().encode("admin"))
.roles("ADMIN");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin().permitAll(); // 开启表单登录
}
}
客户端系统搭建
创建第一个客户端项目,引入Spring Security和OAuth2客户端依赖:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
</dependencies>
配置客户端应用属性文件:
server.port=8081 # OAuth2客户端配置 spring.security.oauth2.client.registration.custom.client-id=client1 spring.security.oauth2.client.registration.custom.client-secret=secret1 spring.security.oauth2.client.registration.custom.scope=read,write spring.security.oauth2.client.registration.custom.authorization-grant-type=authorization_code spring.security.oauth2.client.registration.custom.redirect-uri=http://127.0.0.1:8081/login/oauth2/code/custom # 授权服务器地址配置 spring.security.oauth2.client.provider.custom.authorization-uri=http://127.0.0.1:8080/oauth/authorize spring.security.oauth2.client.provider.custom.token-uri=http://127.0.0.1:8080/oauth/token spring.security.oauth2.client.provider.custom.user-info-uri=http://127.0.0.1:8080/oauth/userinfo
编写客户端安全配置类:
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
public class ClientSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.oauth2Login(); // 开启OAuth2登录
}
}
添加客户端测试接口:
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.security.Principal;
@RestController
public class TestController {
@GetMapping("/hello")
public String hello(Principal principal) {
return "客户端1返回:欢迎用户 " + principal.getName();
}
}
功能验证步骤
按照以下顺序启动服务:
- 启动授权服务器,默认端口8080
- 启动客户端1,端口8081
- 启动客户端2,端口8082,配置与客户端1类似,仅修改端口和客户端ID为client2
验证流程:
- 访问
http://127.0.0.1:8081/hello,会自动跳转到授权服务器登录页 - 输入用户user1和密码123456完成认证,授权后会跳回客户端1,显示欢迎信息
- 此时访问
http://127.0.0.1:8082/hello,无需再次登录即可直接显示客户端2的欢迎信息,说明单点登录生效
常见问题说明
实际落地时需要注意以下几点:
- 令牌存储建议使用JWT或者Redis,避免内存存储重启后丢失
- 客户端密钥和用户信息建议对接数据库存储,不要使用内存配置
- 生产环境需要开启HTTPS,避免令牌被中间人窃取
- 回调地址需要严格校验,避免被恶意篡改导致的安全问题
Spring_SecurityOAuth2单点登录SSO授权服务器修改时间:2026-07-09 08:24:14