【Spring Security】入门:SecurityFilterChain、表单登录与密码加密
🔑 关键词:Java、Spring Security、认证授权、SecurityFilterChain、UserDetailsService、BCrypt
一、什么是 Spring Security?
Spring Security 是 Spring 生态中的安全框架,提供认证(Authentication)、授权(Authorization)和防护性安全机制。
📌 一句话理解:认证是"你是谁",授权是"你能干什么"。Spring Security 帮你搞定这两件事。
二、认证 vs 授权
| 概念 | 含义 | 举例 |
|---|---|---|
| 认证(Authentication) | 验证用户身份 | 登录:用户名+密码 |
| 授权(Authorization) | 验证用户权限 | 访问:只有管理员能删除用户 |
三、核心架构
3.1 请求处理流程
客户端请求
↓
FilterChain(过滤器链)
↓
UsernamePasswordAuthenticationFilter(处理登录)
↓
AuthenticationManager(认证管理器)
↓
AuthenticationProvider(认证提供者)
↓
UserDetailsService(加载用户信息)
↓
认证成功 → SecurityContext(存储认证信息)
认证失败 → AuthenticationEntryPoint(返回 401)
3.2 核心组件
| 组件 | 职责 |
|---|---|
| SecurityFilterChain | 过滤器链,拦截请求进行安全校验 |
| AuthenticationManager | 认证管理器,协调认证流程 |
| AuthenticationProvider | 认证提供者,执行具体认证逻辑 |
| UserDetailsService | 加载用户信息(从数据库查) |
| SecurityContext | 存储当前用户的认证信息 |
| PasswordEncoder | 密码编码器(如 BCrypt) |
四、Spring Boot 整合 Spring Security
4.1 引入依赖
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
4.2 默认行为
引入依赖后,Spring Security 自动生效:
-
所有请求都需要认证
-
默认用户名:
user -
默认密码:启动时控制台打印
Using generated security password: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
五、自定义安全配置
5.1 SecurityFilterChain 配置
java
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// 放行规则
.authorizeHttpRequests(auth -> auth
.requestMatchers("/login", "/register", "/error").permitAll() // 放行
.requestMatchers("/admin/**").hasRole("ADMIN") // 需要管理员角色
.anyRequest().authenticated() // 其他请求需要认证
)
// 表单登录
.formLogin(form -> form
.loginPage("/login") // 自定义登录页
.loginProcessingUrl("/doLogin") // 登录请求路径
.defaultSuccessUrl("/home") // 登录成功跳转
.failureUrl("/login?error") // 登录失败跳转
.permitAll()
)
// 退出登录
.logout(logout -> logout
.logoutUrl("/logout")
.logoutSuccessUrl("/login?logout")
.permitAll()
)
// CSRF(前后端分离时通常关闭)
.csrf(csrf -> csrf.disable());
return http.build();
}
}
5.2 关键配置说明
| 方法 | 作用 |
|---|---|
permitAll() |
无需认证即可访问 |
authenticated() |
需要认证(登录即可) |
hasRole("ADMIN") |
需要 ADMIN 角色 |
hasAuthority("user:add") |
需要 user:add 权限 |
anyRequest() |
匹配所有其他请求 |
六、UserDetailsService
6.1 自定义用户DetailsService
java
@Service
public class MyUserDetailsService implements UserDetailsService {
@Autowired
private UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// 从数据库查询用户
User user = userMapper.selectByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("用户不存在:" + username);
}
// 查询用户权限
List<GrantedAuthority> authorities = user.getRoles().stream()
.map(role -> new SimpleGrantedAuthority("ROLE_" + role.getName()))
.collect(Collectors.toList());
// 返回 UserDetails 对象
return new org.springframework.security.core.userdetails.User(
user.getUsername(),
user.getPassword(),
authorities
);
}
}
6.2 UserDetails 说明
| 属性 | 说明 |
|---|---|
username |
用户名 |
password |
加密后的密码 |
authorities |
权限列表 |
isAccountNonExpired() |
账号是否未过期 |
isAccountNonLocked() |
账号是否未锁定 |
isCredentialsNonExpired() |
凭证是否未过期 |
isEnabled() |
账号是否启用 |
七、BCrypt 密码加密
7.1 配置密码编码器
java
@Configuration
public class SecurityConfig {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
7.2 注册时加密密码
java
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
@Autowired
private PasswordEncoder passwordEncoder;
public void register(User user) {
// 加密密码
String encodedPassword = passwordEncoder.encode(user.getPassword());
user.setPassword(encodedPassword);
userMapper.insert(user);
}
}
7.3 BCrypt 特点
| 特点 | 说明 |
|---|---|
| 不可逆 | 单向哈希,无法反解 |
| 自带盐值 | 每次加密结果不同 |
| 可调强度 | 通过 strength 参数控制计算复杂度 |
| 安全推荐 | 目前业界推荐的密码加密方案 |
java
// 验证密码
boolean matches = passwordEncoder.matches("123456", encodedPassword);
// true: 密码匹配, false: 不匹配
八、获取当前登录用户
java
@RestController
public class UserController {
@GetMapping("/current")
public String currentUser() {
// 方式一:通过 SecurityContextHolder
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String username = auth.getName();
Collection<? extends GrantedAuthority> authorities = auth.getAuthorities();
return "当前用户:" + username + ", 权限:" + authorities;
}
// 方式二:通过方法参数注入
@GetMapping("/current2")
public String currentUser2(@AuthenticationPrincipal UserDetails userDetails) {
return "当前用户:" + userDetails.getUsername();
}
}
九、面试高频问题
Q1:Spring Security 的核心组件有哪些?
答 :
SecurityFilterChain(过滤器链)、AuthenticationManager(认证管理器)、AuthenticationProvider(认证提供者)、UserDetailsService(加载用户信息)、SecurityContext(存储认证信息)、PasswordEncoder(密码编码器)。
Q2:Spring Security 的认证流程?
答 :请求到达 FilterChain →
UsernamePasswordAuthenticationFilter拦截登录请求 → 将用户名密码封装为Authentication对象 →AuthenticationManager调用AuthenticationProvider→AuthenticationProvider调用UserDetailsService加载用户信息 → 比对密码(PasswordEncoder)→ 成功则将认证信息存入SecurityContext。
Q3:BCrypt 的优点?
答:①不可逆单向哈希;②自动加盐,相同密码每次加密结果不同;③可调节计算强度(strength),随着硬件升级可以增加难度;④是目前业界推荐的密码存储方案。
十、总结
| 知识点 | 核心要点 |
|---|---|
| 认证与授权 | 认证=你是谁,授权=你能干什么 |
| SecurityFilterChain | 配置安全规则的核心入口 |
| UserDetailsService | 从数据库加载用户信息 |
| BCrypt | 推荐的密码加密方案 |
| SecurityContext | 存储当前用户的认证信息 |
📝 下一篇预告:《Spring Security 授权与高级功能》,详解 URL/方法级权限控制、CSRF、Remember-Me。