本文目录导读:

- 第一阶段:快速入门与默认行为
- 第二阶段:最常用的配置(内存用户 + 表单登录)
- 第三阶段:自定义 Security 配置类(最主流方式)
- 第四阶段:使用数据库进行用户认证(生产环境)
- 第五阶段:保护 REST API(JWT / 无状态)
- 常见问题与技巧
- 总结配置步骤
Spring Boot 的安全(Security)配置主要通过 Spring Security 来实现,官方提供了一个非常方便的 starter 包:spring-boot-starter-security。
以下是针对不同场景的详细配置指南,从入门到常用自定义设置。
第一阶段:快速入门与默认行为
在 pom.xml 或 build.gradle 中添加依赖后,无需任何额外代码,应用即被保护。
添加依赖(Maven)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
Gradle
implementation 'org.springframework.boot:spring-boot-starter-security'
默认生效规则
- 所有端点都被保护:除了
/actuator/health等极少数端点外,所有HTTP接口都需要认证。 - 自动生成密码:启动日志中会打印一行:
Using generated security password: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx。 - 默认用户名:
user。 - 登录页面:Spring Security 会提供一个默认的 HTML 登录页面,访问
/login即可。 - 登出:访问
/logout。
第二阶段:最常用的配置(内存用户 + 表单登录)
通常你不会想用启动时随机生成的密码,而是在 application.yml 或 application.properties 中配置固定的用户名和密码。
配置 application.yml
spring:
security:
user:
name: admin # 自定义用户名
password: 123456 # 自定义密码
roles: ADMIN # 用户角色(可选)
这种方式适合开发环境或极简应用,对于生产环境,建议使用数据库或 OAuth2。
第三阶段:自定义 Security 配置类(最主流方式)
为了自定义安全过滤规则、资源放行、加密方式等,你需要创建一个配置类。
创建安全配置类 SecurityConfig.java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity // 启用 Spring Security 的 Web 安全功能
public class SecurityConfig {
// 核心:定义安全过滤链(替换旧的 WebSecurityConfigurerAdapter)
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// 1. 授权规则
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/", "/home", "/public/**").permitAll() // 放行公开路径
.requestMatchers("/admin/**").hasRole("ADMIN") // 需要 ADMIN 角色
.requestMatchers("/user/**").hasAnyRole("USER", "ADMIN") // 需要 USER 或 ADMIN 角色
.anyRequest().authenticated() // 其余所有请求都需要登录
)
// 2. 登录配置(使用表单登录)
.formLogin(form -> form
.loginPage("/login") // 自定义登录页(需自己写Controller)
.permitAll() // 允许所有人访问登录页
.defaultSuccessUrl("/dashboard", true) // 登录成功后跳转
.failureUrl("/login?error=true")
)
// 3. 注销配置
.logout(logout -> logout
.logoutSuccessUrl("/login?logout")
.permitAll()
)
// 4. 其他功能(此处禁用CSRF便于Postman测试,生产环境建议开启)
.csrf(csrf -> csrf.disable());
return http.build();
}
// 配置内存用户(测试用,生产环境建议用数据库)
@Bean
public UserDetailsService users() {
// InMemoryUserDetailsManager 是官方提供的简易实现
return new InMemoryUserDetailsManager(
User.withUsername("admin") // 用户名
.password("{noop}admin123") // {noop} 表示密码不加密(明文)
.roles("ADMIN")
.build(),
User.withUsername("user")
.password("{noop}user123")
.roles("USER")
.build()
);
}
// (可选)配置密码编码器,这样就不需要 {noop} 了
// @Bean
// public PasswordEncoder passwordEncoder() {
// return new BCryptPasswordEncoder(); // 推荐使用 BCrypt
// }
}
常见注解说明
@EnableWebSecurity:标志这是一个 Spring Security 配置类。SecurityFilterChain:代替了过时的WebSecurityConfigurerAdapter(Spring Boot 2.7+ 推荐方式)。UserDetailsService:负责从内存、数据库、LDAP等地方加载用户信息。
第四阶段:使用数据库进行用户认证(生产环境)
内存用户只适用于测试,生产环境中,用户信息通常存储在数据库中。
配置密码编码器
在配置类中加入:
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(); // 推荐使用 BCrypt 哈希
}
实现 UserDetailsService 接口
你需要创建一个类从数据库查询用户,并返回 UserDetails 对象。
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
@Service
public class DatabaseUserDetailsService implements UserDetailsService {
// 假设这是你从数据库查询用户的服务
private final UserRepository userRepository;
// 替换为自己的数据库访问层
public DatabaseUserDetailsService(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
// 1. 从数据库查询用户(可自行扩展)
MyUser myUser = userRepository.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("User not found"));
// 2. 将查询结果转换为 Spring Security 的 UserDetails
return User.builder()
.username(myUser.getUsername())
.password(myUser.getPassword()) // 注意:这里必须是 BCrypt 加密后的密码
.roles(myUser.getRole()) // 假设数据库中的 role 字段是 "ADMIN" 或 "USER"
.build();
}
}
配置类中使用自定义的 UserDetailsService
@Configuration
@EnableWebSecurity
public class SecurityConfig {
private final DatabaseUserDetailsService userDetailsService;
public SecurityConfig(DatabaseUserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// ... 同上,省略路径配置
return http.build();
}
// 注册自定义 UserDetailsService 和密码编码器
@Bean
public AuthenticationManager authenticationManager(
AuthenticationConfiguration authenticationConfiguration)
throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
}
(注意:如果使用了自定义 UserDetailsService,需要再注入一个 PasswordEncoder,并在 AuthenticationProvider 中设置它们,实际 Spring Boot 会自动装配,只需在配置类中声明 DaoAuthenticationProvider 或利用自动配置即可。)
简化做法: 直接在 SecurityConfig 中声明 DaoAuthenticationProvider:
@Bean
public AuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(userDetailsService);
provider.setPasswordEncoder(passwordEncoder());
return provider;
}
第五阶段:保护 REST API(JWT / 无状态)
如果你的应用是前后端分离的 REST API,不应使用表单登录,而是使用 JWT 或 Basic Auth。
使用 HTTP Basic 认证(简单,但不推荐生产)
http.httpBasic(Customizer.withDefaults()); // 替代 formLogin
使用 JWT(标准做法)
需要额外步骤:
- 不启用
formLogin和session。 - 创建一个自定义的
OncePerRequestFilter来解析 JWT Token。 - 将
SecurityContextHolder设置认证信息。 - 在
SecurityFilterChain中把该过滤器添加到UsernamePasswordAuthenticationFilter之前。
常见问题与技巧
- 密码格式:如果使用
{noop}前缀,密码不加密,正式环境必须使用BCryptPasswordEncoder,数据库中存储加密后的哈希值。 - 跨域(CORS):如果是前后端分离,需要配置:
http.cors(Customizer.withDefaults());
并配合
@CrossOrigin注解或CorsConfigurationSourceBean。 - 禁用 CSRF:仅当你的应用是无状态 REST API 时可禁用;如果是传统的服务端模板渲染网站,建议开启(默认开启)。
- 自定义权限:除了角色,还可以使用
@PreAuthorize("hasAuthority('PRIVILEGE_VIEW')")实现细粒度权限控制(需要先添加@EnableMethodSecurity注解)。 - 静态资源放行:如果使用了前端打包工具,记得放行
/static/**,/css/**,/js/**,/images/**。
总结配置步骤
- 添加
spring-boot-starter-security依赖。 - (可选)在
application.yml中配置临时账号密码。 - 创建配置类,定义
SecurityFilterChainBean,配置放行路径、登录方式、CSRF、CORS。 - 定义用户来源:在配置类中定义
UserDetailsService(内存或数据库)。 - 定义密码编码器:
BCryptPasswordEncoder。 - (可选)实现自定义认证过滤器(如 JWT)。
通过以上步骤,你可以快速搭建一个安全的 Spring Boot 应用,如果遇到问题,先确认版本是否一致(Spring Boot 3.x 和 2.x 在 Java 17+ 的一些 API 上略有不同,但以上代码主要兼容 3.x)。