目录
一、什么是 Spring Security?
✅ 核心功能:
二、Spring Security 核心概念
1. Authentication(认证)
2. UserDetails & UserDetailsService
3. PasswordEncoder
4. GrantedAuthority
5. SecurityContext & SecurityContextHolder
三、Spring Security 工作流程(认证过程)
四、常用配置方式(Spring Boot)
1. 引入依赖(Maven)
2. 基础配置类(启用 Web 安全)
3. 自定义 UserDetailsService
五、权限控制(授权 Authorization)
1. 方法级别权限(推荐)
2. 页面级别权限(Thymeleaf)
六、常见自定义扩展
1. 自定义登录成功/失败处理器
2. 自定义权限异常处理
七、与 JWT / 前后端分离集成(简要)
八、最佳实践 & 注意事项
✅ 总结一句话:
学习路径建议:
送你一个完整可运行的最小示例结构:
一、什么是 Spring Security?
Spring Security 是一个功能强大、高度可定制的身份验证(Authentication)和访问控制(Authorization)框架,是保护基于 Spring 的应用的事实标准。
✅ 核心功能:
- 用户登录认证(Authentication)
- 权限控制、角色控制(Authorization)
- 防止 CSRF、会话固定、点击劫持等攻击
- 支持多种登录方式:表单登录、HTTP Basic、OAuth2、JWT、LDAP 等
- 与 Spring Boot 无缝集成
二、Spring Security 核心概念
1. Authentication
(认证)
- 代表“当前用户是谁”,包含用户名、密码、权限等。
- 由
AuthenticationManager
管理认证过程。
2. UserDetails
& UserDetailsService
UserDetails
:封装用户信息(用户名、密码、权限、是否锁定等)UserDetailsService
:根据用户名加载UserDetails
@Override
public UserDetails loadUserByUsername(String username) {
// 从数据库查用户 → 返回 UserDetails(含加密密码 + 权限)
}
3. PasswordEncoder
- 用于加密密码和比对密码。
- 永远不要存储明文密码!
- 常用实现:
BCryptPasswordEncoder
,SCryptPasswordEncoder
,Pbkdf2PasswordEncoder
// 注册时:
user.setPassword(passwordEncoder.encode(rawPassword));
// 登录时(框架自动调用):
passwordEncoder.matches(rawPassword, encodedPassword); // true/false
4. GrantedAuthority
- 代表一个权限,如
"ROLE_ADMIN"
、"user:delete"
。 - 通常以
ROLE_
开头表示角色,其它表示具体权限。
5. SecurityContext
& SecurityContextHolder
- 存储当前登录用户的信息(
Authentication
对象)。 - 可在任何地方获取当前用户:
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String username = auth.getName();
三、Spring Security 工作流程(认证过程)
sequenceDiagram
participant User
participant Filter as FilterChain (Spring Security)
participant Provider as AuthenticationProvider
participant Service as UserDetailsService
participant Encoder as PasswordEncoder
User->>Filter: 提交用户名/密码
Filter->>Provider: 调用 authenticate()
Provider->>Service: loadUserByUsername(username)
Service-->>Provider: 返回 UserDetails(含加密密码)
Provider->>Encoder: matches(输入密码, 数据库加密密码)
alt 匹配成功
Encoder-->>Provider: true
Provider-->>Filter: 返回认证成功 Authentication
Filter->>User: 登录成功,跳转
else 匹配失败
Encoder-->>Provider: false
Provider-->>Filter: 抛出异常
Filter->>User: 登录失败
end
四、常用配置方式(Spring Boot)
1. 引入依赖(Maven)
org.springframework.boot
spring-boot-starter-security
2. 基础配置类(启用 Web 安全)
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authz -> authz
.requestMatchers("/login", "/register", "/css/**").permitAll()
.requestMatchers("/admin/**").hasRole("ADMIN")
.requestMatchers("/user/**").hasAnyRole("USER", "ADMIN")
.anyRequest().authenticated()
)
.formLogin(form -> form
.loginPage("/login") // 自定义登录页
.defaultSuccessUrl("/home") // 登录成功跳转
.permitAll()
)
.logout(logout -> logout
.logoutSuccessUrl("/login?logout")
.permitAll()
);
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(); // 推荐使用 BCrypt
}
}
3. 自定义 UserDetailsService
@Component
public class MyUserServiceImpl implements UserDetailsService {
@Autowired
private UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userMapper.findUserByName(username);
if (user == null) throw new UsernameNotFoundException("用户不存在");
// ✅ 直接返回数据库中的加密密码(注册时已加密存储!)
return User.builder()
.username(user.getUsername())
.password(user.getSupwd()) // ← 不要再 encode!
.roles("USER") // 或者 .authorities(getAuthorities())
.build();
}
}
五、权限控制(授权 Authorization)
1. 方法级别权限(推荐)
@Service
public class ArticleService {
@PreAuthorize("hasRole('ADMIN')") // 需要 ADMIN 角色
public void deleteArticle(Long id) {
// ...
}
@PreAuthorize("hasAuthority('article:edit')") // 需要具体权限
public void editArticle(Article article) {
// ...
}
@PostAuthorize("returnObject.owner == authentication.name")
public Article getArticle(Long id) {
// 返回后检查:只有文章主人才能看
}
}
⚠️ 要启用方法级权限,需在配置类加:
@EnableMethodSecurity
@Configuration
@EnableWebSecurity
@EnableMethodSecurity // ← 启用 @PreAuthorize 等注解
public class SecurityConfig { ... }
2. 页面级别权限(Thymeleaf)
管理后台
需引入:
org.thymeleaf.extras
thymeleaf-extras-springsecurity6
六、常见自定义扩展
1. 自定义登录成功/失败处理器
@Component
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response,
Authentication authentication) throws IOException {
response.sendRedirect("/home?loginSuccess");
}
}
在配置中使用:
.formLogin(form -> form
.successHandler(mySuccessHandler)
.failureHandler(myFailureHandler)
)
2. 自定义权限异常处理
@Component
public class MyAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException {
response.sendRedirect("/403");
}
}
配置:
.exceptionHandling(ex -> ex
.accessDeniedHandler(myAccessDeniedHandler)
)
七、与 JWT / 前后端分离集成(简要)
如果你是前后端分离项目(如 Vue + Spring Boot),通常不用 Session,改用 JWT:
- 用户 POST
/login
提交用户名密码 - 后端验证成功 → 生成 JWT Token 返回
- 前端后续请求在 Header 中携带
Authorization: Bearer <token>
- 后端用 Filter 解析 Token → 设置
SecurityContext
⚠️ 此时
UserDetailsService
依然有用 —— 用于从 Token 中的用户名加载用户权限!
八、最佳实践 & 注意事项
项目 | 建议 |
---|---|
密码存储 | 必须加密(BCrypt 最常用) |
密码比对 | 交给 Spring Security,不要手动比对 |
权限设计 | 角色(ROLE_) + 细粒度权限(user:delete)结合 |
登录页 | 可自定义,但路径要 permitAll |
CSRF | 表单登录默认开启,JWT 项目可关闭 |
调试 | 可临时 .authorizeHttpRequests(authz -> authz.anyRequest().permitAll()) 放行所有 |
✅ 总结一句话:
Spring Security = 认证(你是谁)+ 授权(你能干什么)+ 安全防护,你只需要提供“用户数据”和“权限规则”,框架自动完成验证和拦截。
学习路径建议:
- 先跑通表单登录 + 自定义 UserDetailsService
- 学会配置 URL 权限控制
- 掌握方法级权限
@PreAuthorize
- 学习自定义处理器(登录成功/失败、无权限)
- 进阶:JWT、OAuth2、方法权限表达式、动态权限
送你一个完整可运行的最小示例结构:
src/
├── controller/
│ └── LoginController.java // 登录页、首页
├── service/
│ └── MyUserServiceImpl.java // loadUserByUsername
├── config/
│ └── SecurityConfig.java // 权限配置 + PasswordEncoder
└── entity/
└── User.java // 用户实体(含加密密码字段)