Spring Security 超详细使用教程:接入 Spring Boot 与前后端分离
引言:Spring Security,Spring Boot 安全的“守护神”
Spring Security 是 Spring 生态中处理认证(Authentication)和授权(Authorization)的强大框架,它无缝集成 Spring Boot,提供从基本认证到 OAuth2 的全面解决方案。在前后端分离架构中(如 React/Vue 前端 + Spring Boot 后端),Spring Security 常结合 JWT(JSON Web Token)实现无状态认证,避免传统 Session 的跨域问题。根据官方指南,Spring Security 能轻松保护 REST API,确保只有授权用户访问资源。 2026 年,随着 Spring Boot 3.x 的普及,这一框架支持虚拟线程和 GraalVM Native 编译,提升了性能和安全性。本教程从基础接入入手,逐步深入前后端分离实战,覆盖依赖、配置、JWT 集成和常见坑。目标:读完后,你能独立构建一个安全的 API 系统,提升应用安全性 50%+。预计阅读时长:30 分钟。准备 IntelliJ IDEA 和 Maven?立即新建 Spring Boot 项目测试基本认证!
核心概念:Spring Security 基础速览
Spring Security 的核心是过滤器链(Filter Chain),它拦截请求,处理认证/授权。以下表格对比关键概念(基于 Spring Security 6.x,兼容 Boot 3.x):
| 概念 | 定义与作用 | 关键组件/注解 | 前后端分离适用性 | 常见误区 |
|---|---|---|---|---|
| 认证(Authentication) | 验证用户身份(如用户名/密码、JWT) | UserDetailsService, AuthenticationManager | 高:用 JWT 令牌替换 Session | 忽略密码加密(BCrypt) |
| 授权(Authorization) | 检查权限(如角色/方法级) | @PreAuthorize, SecurityFilterChain | 高:基于 JWT 声明(claims) | 过度配置导致性能瓶颈 |
| 过滤器链 | 拦截请求的过滤器序列 | HttpSecurity 配置 | 中:自定义 JWT 过滤器 | 默认启用 CSRF 冲突 CORS |
| JWT 集成 | 无状态令牌,用于前后端分离 | JwtAuthenticationToken | 高:API 首选 | 密钥泄露/过期未处理 |
| OAuth2 | 第三方登录(如 Google) | @EnableOAuth2Client | 高:社交登录 | 配置 issuer-uri 错误 |
解读:前后端分离时,禁用 Session(stateless),用 JWT 携带用户信息。默认 Spring Security 启用基本认证,需自定义配置。
依赖与项目准备
步骤1:创建 Spring Boot 项目
- 使用 Spring Initializr(https://start.spring.io)生成项目:选择 Spring Boot 3.x、Java 21+、Maven。
- 添加依赖:Web(spring-boot-starter-web)、Security(spring-boot-starter-security)、JWT(spring-boot-starter-oauth2-resource-server 或 jjwt)。
- pom.xml 示例:
<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</groupId>
<artifactId>spring-security-oauth2-resource-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-jose</artifactId>
</dependency>
<dependency> <!-- JWT 解析 -->
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.12.3</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.12.3</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.12.3</version>
<scope>runtime</scope>
</dependency>
</dependencies>
步骤2:基本配置
- 添加 Security 后,Spring Boot 默认启用基本认证(用户名 user,密码控制台打印)。测试:运行应用,访问 http://localhost:8080,弹出登录框。
基础认证配置:用户名/密码验证
步骤3:自定义用户服务
- 创建 UserDetailsService 实现类,加载用户数据(可从数据库)。
- 代码示例(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.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
public class SecurityConfig {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(); // 密码加密
}
@Bean
public UserDetailsService userDetailsService() {
UserDetails user = User.withUsername("admin")
.password(passwordEncoder().encode("123456"))
.roles("ADMIN")
.build();
return new InMemoryUserDetailsManager(user); // 内存用户,生产用数据库
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/public/**").permitAll() // 公开路径
.anyRequest().authenticated() // 其他需认证
)
.formLogin(form -> form // 表单登录
.loginPage("/login") // 自定义登录页(前后端分离可忽略)
.permitAll()
)
.logout(logout -> logout.permitAll());
return http.build();
}
}
- 测试:访问受保护路径,输入 admin/123456 登录。
前后端分离:JWT 认证集成
前后端分离时,禁用表单登录和 CSRF,用 JWT 处理认证。
步骤4:JWT 配置
- 创建 JWT 工具类:
import io.jsonwebtoken.*;
import java.util.Date;
public class JwtUtils {
private static final String SECRET = "your_secret_key"; // 密钥
private static final long EXPIRATION = 86400000; // 1天
public static String generateToken(String username) {
return Jwts.builder()
.setSubject(username)
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION))
.signWith(Keys.hmacShaKeyFor(SECRET.getBytes()))
.compact();
}
public static String getUsernameFromToken(String token) {
return Jwts.parserBuilder()
.setSigningKey(Keys.hmacShaKeyFor(SECRET.getBytes()))
.build()
.parseClaimsJws(token)
.getBody()
.getSubject();
}
public static boolean validateToken(String token) {
try {
Jwts.parserBuilder().setSigningKey(Keys.hmacShaKeyFor(SECRET.getBytes())).build().parseClaimsJws(token);
return true;
} catch (Exception e) {
return false;
}
}
}
步骤5:自定义 JWT 过滤器
- 更新 SecurityConfig:
// ... 省略前部分
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable()) // 前后端分离禁用 CSRF
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) // 无状态
.authorizeHttpRequests(auth -> auth
.requestMatchers("/login").permitAll()
.anyRequest().authenticated()
)
.addFilterBefore(new JwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class); // 自定义过滤器
return http.build();
}
- JwtAuthenticationFilter.java:
import jakarta.servlet.FilterChain;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.filter.OncePerRequestFilter;
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws Exception {
String token = request.getHeader("Authorization");
if (token != null && token.startsWith("Bearer ")) {
token = token.substring(7);
if (JwtUtils.validateToken(token)) {
String username = JwtUtils.getUsernameFromToken(token);
// 从UserDetailsService加载用户
UserDetails userDetails = userDetailsService().loadUserByUsername(username);
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(auth);
}
}
filterChain.doFilter(request, response);
}
}
步骤6:登录接口生成 JWT
- LoginController.java:
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class LoginController {
private final AuthenticationManager authenticationManager;
public LoginController(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
@PostMapping("/login")
public String login(@RequestBody LoginRequest request) {
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(request.getUsername(), request.getPassword())
);
return JwtUtils.generateToken(request.getUsername());
}
}
public class LoginRequest {
private String username;
private String password;
// getters/setters
}
- 前端:用 Axios 发送 POST /login,获取 JWT,后续请求加 Header: Authorization: Bearer {token}。
授权与方法级安全
步骤7:角色授权
- 在 SecurityConfig 加
@EnableMethodSecurity。 - Controller 示例:
@RestController
public class AdminController {
@GetMapping("/admin")
@PreAuthorize("hasRole('ADMIN')") // 方法级授权
public String admin() {
return "Admin Access";
}
}
常见问题与优化
- CORS:前后端分离加 CORS 配置:
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedOrigins(List.of("http://localhost:3000")); // 前端地址
config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE"));
config.setAllowedHeaders(List.of("*"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return source;
}
- 性能:大表 JWT 验证用缓存;生产用 RSA 密钥签名。
- OAuth2:扩展到第三方登录,配置 issuer-uri 和 client-id< g rok:render type=”render_inline_citation”>
9
。
结语:Spring Security,构建安全的 API 堡垒
从基本认证到 JWT 前后端分离,Spring Security 让安全配置变得优雅而强大——在春川的春日午后(当前 KST 11:30,2026.3.7),试着运行这个配置,Postman 测试 /login 获取 JWT,你将感受到安全的脉动!实践挑战:集成数据库用户存储。需 OAuth2 扩展或代码调试?分享你的项目细节,我帮优化。参考:Spring 官方指南与 Baeldung 教程。 Go secure, build robust!