深入理解 Spring Security 6:从认证到授权的最佳实践
前言
在现代 Web 应用开发中,安全性至关重要。Spring Security 作为 Spring 生态中最强大的安全框架,为 Java 开发者提供了完整的身份认证、授权控制、防护等能力。随着 Spring Security 6 的发布,官方调整了一些核心 API,并且与 Spring Boot 3 深度集成,以提升安全性和可维护性。
本篇文章将从零基础入门,逐步解析 Spring Security 6 的核心概念,并通过完整代码示例,掌握用户认证、授权管理、基于 JWT 令牌的无状态认证、CSRF 保护等关键技术,助你构建安全可靠的 Java Web 应用。🚀
一、Spring Security 6 主要变化
Spring Security 6 针对 Spring Boot 3 + JDK 17 进行了优化,主要变化包括:
- 废弃
WebSecurityConfigurerAdapter
,改用SecurityFilterChain
- 默认基于
PasswordEncoder
进行密码哈希 - 新的
AuthorizationManager
API - 默认开启 CSRF 保护
- OAuth 2.0 与 OpenID Connect (OIDC) 支持
- JWT 令牌集成更加方便
二、Spring Security 6 项目初始化
2.1 创建 Spring Boot 3 项目
访问 Spring Initializr 生成项目,选择:
- Spring Boot 版本:
3.x
- Java 版本:
17
- 依赖项:
- Spring Web(构建 REST API)
- Spring Security(安全框架)
- Spring Data JPA(数据库访问)
- H2 Database(内存数据库)
- Lombok(简化 Java 代码)
或者使用命令行创建:
curl https://start.spring.io/starter.zip -d dependencies=web,security,data-jpa,h2,lombok -o demo.zip
三、Spring Security 6 认证与授权
3.1 配置 Spring Security
Spring Security 6 不再使用 WebSecurityConfigurerAdapter
,而是改用 SecurityFilterChain
:
// config/SecurityConfig.java
package com.example.demo.config;
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.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http
.csrf(csrf -> csrf.disable()) // 关闭 CSRF 保护(生产环境需开启)
.authorizeHttpRequests(auth -> auth
.requestMatchers("/admin/**").hasRole("ADMIN")
.requestMatchers("/user/**").hasRole("USER")
.anyRequest().authenticated()
)
.formLogin(login -> login
.defaultSuccessUrl("/welcome", true)
)
.logout(logout -> logout
.logoutSuccessUrl("/login")
)
.build();
}
@Bean
public UserDetailsService userDetailsService() {
UserDetails user = User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER")
.build();
UserDetails admin = User.withDefaultPasswordEncoder()
.username("admin")
.password("password")
.roles("ADMIN")
.build();
return new InMemoryUserDetailsManager(user, admin);
}
}
重点解析:
SecurityFilterChain
替代WebSecurityConfigurerAdapter
authorizeHttpRequests
进行 URL 访问控制formLogin
启用表单登录userDetailsService
定义用户信息,默认密码哈希
3.2 测试安全机制
运行项目后,访问:
http://localhost:8080/user
→ 需USER
角色http://localhost:8080/admin
→ 需ADMIN
角色http://localhost:8080/login
→ 登录页面
输入:
- 用户名:
user
或admin
- 密码:
password
成功后跳转到 /welcome
。
四、集成数据库用户认证
4.1 创建 User
实体
// entity/User.java
package com.example.demo.entity;
import jakarta.persistence.*;
import lombok.Data;
@Entity
@Data
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String password;
private String role;
}
4.2 创建 UserRepository
// repository/UserRepository.java
package com.example.demo.repository;
import com.example.demo.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByUsername(String username);
}
4.3 自定义 UserDetailsService
// service/UserDetailsServiceImpl.java
package com.example.demo.service;
import com.example.demo.entity.User;
import com.example.demo.repository.UserRepository;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Service;
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
private final UserRepository userRepository;
public UserDetailsServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("User not found"));
return User.withUsername(user.getUsername())
.password(user.getPassword())
.roles(user.getRole())
.build();
}
}
这里从数据库加载用户信息,并转换为
UserDetails
对象。
4.4 配置 PasswordEncoder
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
数据库中的密码应使用 BCrypt
进行加密存储。
五、基于 JWT 进行无状态认证
Spring Security 6 结合 JWT 实现无状态认证:
- 用户登录 → 生成 JWT 令牌
- 前端请求携带 JWT → 服务器解析验证
- 授权访问 API
5.1 生成 JWT 令牌
String token = Jwts.builder()
.setSubject(user.getUsername())
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + 86400000)) // 1 天
.signWith(SignatureAlgorithm.HS256, secretKey)
.compact();
完整的 JWT 实现可以参考 Spring Security + JWT 教程。
六、总结
功能 | Spring Security 6 方案 |
---|---|
认证方式 | 数据库用户认证 |
授权管理 | 基于角色/权限控制 |
密码加密 | BCrypt 加密存储 |
无状态认证 | JWT 令牌 |
CSRF 保护 | 默认开启 |
Spring Security 6 结合 Spring Boot 3 提供了更强大的安全能力,涵盖了表单登录、数据库认证、JWT 认证、角色授权等关键功能,希望本文对你有所帮助!🚀