1. 概述
本文将深入探讨 Spring Boot 对安全配置的约定优于配置理念。我们将聚焦默认安全配置的实现原理,以及如何根据实际需求禁用或自定义这些配置。
2. 默认安全配置
为 Spring Boot 应用添加安全功能,只需引入安全启动器依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
该依赖会自动加载 SecurityAutoConfiguration
类,其中包含初始/默认安全配置。注意这里未指定版本号,假设项目已使用 Boot 作为父 POM。
默认情况下,应用会启用认证功能,并通过内容协商机制决定使用 Basic 认证还是表单登录。
系统预定义了以下配置属性:
spring.security.user.name
spring.security.user.password
若未通过 spring.security.user.password
配置密码,启动时会随机生成默认密码并打印到控制台:
Using default security password: c8be15de-4488-4490-9dc6-fab3f91435c6
更多默认配置可参考 Spring Boot 通用应用属性 的安全属性章节。
3. 禁用自动配置
要禁用安全自动配置并添加自定义配置,需排除 SecurityAutoConfiguration
类。可通过以下两种方式实现:
方式一:注解排除
@SpringBootApplication(exclude = { SecurityAutoConfiguration.class })
public class SpringBootSecurityApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootSecurityApplication.class, args);
}
}
方式二:配置文件排除
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration
⚠️ 踩坑提醒:某些场景下仅排除 SecurityAutoConfiguration
可能不够。例如当类路径包含 Actuator 时,另一个自动配置类依赖我们刚排除的类,会导致启动失败。此时需额外排除 ManagementWebSecurityAutoConfiguration
。
3.1 禁用 vs 覆盖自动配置
禁用与覆盖自动配置有本质区别:
禁用:相当于完全移除 Spring Security 的自动配置,需从头构建安全体系。适用于:
- 集成自定义安全提供商
- 将已有安全配置的旧版 Spring 应用迁移至 Boot
覆盖:保留自动配置基础,通过添加自定义配置类进行扩展。这是推荐方式,因为只需在现有基础上调整即可满足需求。
✅ 经验之谈:大多数情况下无需完全禁用自动配置,Spring Boot 的设计本就支持通过自定义配置覆盖默认行为。
4. 配置 Spring Boot 安全
选择禁用自动配置后,需提供完整的安全配置。最简单的方式是通过属性文件修改默认值,例如覆盖默认密码:
spring.security.user.password=password
若需更灵活配置(如多用户多角色),需使用完整的 @Configuration
类:
@Configuration
@EnableWebSecurity
public class BasicConfiguration {
@Bean
public InMemoryUserDetailsManager userDetailsService(PasswordEncoder passwordEncoder) {
UserDetails user = User.withUsername("user")
.password(passwordEncoder.encode("password"))
.roles("USER")
.build();
UserDetails admin = User.withUsername("admin")
.password(passwordEncoder.encode("admin"))
.roles("USER", "ADMIN")
.build();
return new InMemoryUserDetailsManager(user, admin);
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http.authorizeHttpRequests(request -> request.anyRequest()
.authenticated())
.httpBasic(Customizer.withDefaults())
.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
return encoder;
}
}
@EnableWebSecurity
注解在禁用默认配置时必不可少,缺失会导致启动失败。
⚠️ 重要:Spring Boot 2 中必须使用 PasswordEncoder
设置密码。详情参考 Spring Security 5 默认密码编码器指南。
可通过以下集成测试验证配置:
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = RANDOM_PORT)
public class BasicConfigurationIntegrationTest {
TestRestTemplate restTemplate;
URL base;
@LocalServerPort int port;
@Before
public void setUp() throws MalformedURLException {
restTemplate = new TestRestTemplate("user", "password");
base = new URL("http://localhost:" + port);
}
@Test
public void whenLoggedUserRequestsHomePage_ThenSuccess()
throws IllegalStateException, IOException {
ResponseEntity<String> response =
restTemplate.getForEntity(base.toString(), String.class);
assertEquals(HttpStatus.OK, response.getStatusCode());
assertTrue(response.getBody().contains("Baeldung"));
}
@Test
public void whenUserWithWrongCredentials_thenUnauthorizedPage()
throws Exception {
restTemplate = new TestRestTemplate("user", "wrongpassword");
ResponseEntity<String> response =
restTemplate.getForEntity(base.toString(), String.class);
assertEquals(HttpStatus.UNAUTHORIZED, response.getStatusCode());
assertTrue(response.getBody().contains("Unauthorized"));
}
}
所有 Spring Security 支持的功能均可通过 Boot 实现,因为其底层依赖 Spring Security。
5. Spring Boot OAuth2 自动配置(旧版实现)
Spring Boot 为 OAuth2 提供专用自动配置支持。Spring Boot 1.x 的 Spring Security OAuth 在后续版本中被移除,改用 Spring Security 5 原生支持(见下节)。
使用旧版实现需添加 Maven 依赖:
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
</dependency>
该依赖会触发 OAuth2AutoConfiguration
中的自动配置机制。
5.1 OAuth2 授权服务器自动配置
若需将应用作为 OAuth2 提供商,使用 @EnableAuthorizationServer
。启动时日志会自动生成:
- 客户端 ID 和密钥
- Basic 认证随机密码
Using default security password: a81cb256-f243-40c0-a585-81ce1b952a98
security.oauth2.client.client-id = 39d2835b-1f87-4a77-9798-e2975f36972e
security.oauth2.client.client-secret = f1463f8b-0791-46fe-9269-521b86c55b71
使用这些凭据获取访问令牌:
curl -X POST -u 39d2835b-1f87-4a77-9798-e2975f36972e:f1463f8b-0791-46fe-9269-521b86c55b71 \
-d grant_type=client_credentials \
-d username=user \
-d password=a81cb256-f243-40c0-a585-81ce1b952a98 \
-d scope=write http://localhost:8080/oauth/token
更多细节参考我们的 OAuth2 文章。
5.2 其他 OAuth2 自动配置场景
Spring Boot OAuth2 还支持:
所有 OAuth2 专用属性见 Spring Boot 通用应用属性。
6. Spring Boot OAuth2 自动配置(新版实现)
新版实现需根据目标类型(授权服务器/资源服务器/客户端)添加对应依赖。
6.1 OAuth2 授权服务器支持
Spring Security OAuth 项目已弃用,Spring 官方不再提供自有授权服务器实现。推荐使用成熟方案如:
- Okta
- Keycloak
- ForgeRock
Spring Boot 简化了这些提供商的集成,Keycloak 配置示例参考:
6.2 OAuth2 资源服务器支持
添加资源服务器依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
最新版本见 Maven Central。
在安全配置中添加 oauth2ResourceServer()
DSL:
@Configuration
public class JWTSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
...
.oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()));
...
}
}
深入解析见 OAuth 2.0 资源服务器指南。
6.3 OAuth2 客户端支持
客户端应用需专用依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
最新版本见 Maven Central。
Spring Security 5 通过 oauth2Login()
DSL 提供原生登录支持。新版 SSO 实现参考 Spring Security OAuth2 单点登录。
7. 总结
本文深入剖析了 Spring Boot 的默认安全配置机制,重点涵盖:
- 安全自动配置的禁用与覆盖方法
- 自定义安全配置的实现
- OAuth2 新旧版本实现的配置差异
✅ 核心要点:
- 默认配置通过
spring-boot-starter-security
激活 - 禁用自动配置需排除
SecurityAutoConfiguration
- 推荐通过自定义配置类覆盖而非完全禁用
- OAuth2 新版实现依赖
spring-boot-starter-oauth2-*
系列依赖
OAuth2 示例代码见 GitHub 仓库:
完整代码参考 Spring Boot 安全模块。