Spring Security 框架
目录
一、什么是 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 工作流程(认证过程)
sequenceDiagramparticipant Userparticipant Filter as FilterChain (Spring Security)participant Provider as AuthenticationProviderparticipant Service as UserDetailsServiceparticipant Encoder as PasswordEncoderUser->>Filter: 提交用户名/密码Filter->>Provider: 调用 authenticate()Provider->>Service: loadUserByUsername(username)Service-->>Provider: 返回 UserDetails(含加密密码)Provider->>Encoder: matches(输入密码, 数据库加密密码)alt 匹配成功Encoder-->>Provider: trueProvider-->>Filter: 返回认证成功 AuthenticationFilter->>User: 登录成功,跳转else 匹配失败Encoder-->>Provider: falseProvider-->>Filter: 抛出异常Filter->>User: 登录失败end
四、常用配置方式(Spring Boot)
1. 引入依赖(Maven)
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId>
</dependency>
2. 基础配置类(启用 Web 安全)
@Configuration
@EnableWebSecurity
public class SecurityConfig {@Beanpublic 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();}@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder(); // 推荐使用 BCrypt}
}
3. 自定义 UserDetailsService
@Component
public class MyUserServiceImpl implements UserDetailsService {@Autowiredprivate UserMapper userMapper;@Overridepublic 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)
<!-- 只有 ADMIN 能看到 -->
<div sec:authorize="hasRole('ADMIN')"><a href="/admin">管理后台</a>
</div><!-- 显示当前用户名 -->
<span sec:authentication="name"></span>
需引入:
<dependency><groupId>org.thymeleaf.extras</groupId><artifactId>thymeleaf-extras-springsecurity6</artifactId>
</dependency>
六、常见自定义扩展
1. 自定义登录成功/失败处理器
@Component
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {@Overridepublic 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 {@Overridepublic 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 // 用户实体(含加密密码字段)