认证流程全景图



当用户提交登录表单时,Spring Security 的认证流程如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| 用户提交表单 ↓ UsernamePasswordAuthenticationFilter 拦截 ↓ 提取 username 和 password ↓ 创建 UsernamePasswordAuthenticationToken(未认证状态) ↓ AuthenticationManager.authenticate() ↓ DaoAuthenticationProvider(默认实现) ↓ UserDetailsService.loadUserByUsername() 加载用户 ↓ PasswordEncoder 比对密码 ↓ 认证成功 → 创建完全认证的 Authentication 对象 ↓ 存入 SecurityContextHolder ↓ 重定向到目标页面
|
UserDetailsService:用户信息的来源
UserDetailsService 是认证的核心接口,只有一个方法:
1 2 3
| public interface UserDetailsService { UserDetails loadUserByUsername(String username) throws UsernameNotFoundException; }
|
你可以实现这个接口,从数据库、LDAP、Redis 等任何地方加载用户信息。
Spring Security 提供了几个内置实现:
JdbcUserDetailsManager:从 JDBC 数据源加载用户
LdapUserDetailsManager:从 LDAP 目录加载用户
InMemoryUserDetailsManager:从内存中加载用户(适合测试)
自定义 UserDetailsService
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| @Service public class CustomUserDetailsService implements UserDetailsService {
@Autowired private UserRepository userRepository;
@Autowired private PasswordEncoder passwordEncoder;
@Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userRepository.findByUsername(username); if (user == null) { throw new UsernameNotFoundException("用户不存在: " + username); } return new org.springframework.security.core.userdetails.User( user.getUsername(), user.getPassword(), user.getEnabled(), !user.getAccountExpired(), !user.getCredentialsExpired(), !user.getAccountLocked(), user.getAuthorities() ); } }
|
PasswordEncoder:密码比对
UserDetailsService 返回的用户密码需要经过 PasswordEncoder 比对:
1 2 3 4 5
| public interface PasswordEncoder { String encode(CharSequence rawPassword); boolean matches(CharSequence rawPassword, String encodedPassword); default boolean upgradeEncoding(String encodedPassword) { return false; } }
|
Spring Security 提供了多种实现:
BCryptPasswordEncoder:推荐使用,内置盐值,成本因子可调
Pbkdf2PasswordEncoder:基于 PBKDF2 的密码编码器
SCryptPasswordEncoder:基于 scrypt 的密码编码器
NoOpPasswordEncoder:明文密码(仅用于测试)
认证失败处理
认证失败时,Spring Security 会记录失败原因并跳转到错误页面。你可以自定义失败处理:
1 2 3 4 5
| http.formLogin() .failureHandler((request, response, exception) -> { response.sendRedirect("/login?error=true"); });
|
这为安全监控提供了切入点:你可以记录失败次数、检测暴力破解、发送安全告警。