认证:内存用户与 UserDetailsService
上一章留下一个问题:用户名、密码从哪来?Spring Security 把"找用户"抽象成 UserDetailsService,把"校验密码"交给 PasswordEncoder + DaoAuthenticationProvider。本章讲从内置用户到自定义查库的完整链路,示例基于 Security 6 / Boot 3。
方式一:配置文件内置用户
最省事的演示方式,适合开发期:
spring:
security:
user:
name: admin
password: '{bcrypt}$2a$10$...' # 存 BCrypt 密文(生成工具见下);明文仅限本地
roles: ADMIN,USER
方式二:内存 UserDetailsService
需要多个用户或启动时动态构造时:
@Configuration
public class UserConfig {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(); // 单向哈希 + 随机盐
}
@Bean
public UserDetailsService users(PasswordEncoder encoder) {
UserDetails admin = User.withUsername("admin")
.password(encoder.encode("123456")) // 输出:$2a$10$...(盐随机,两次结果不同)
.roles("ADMIN", "USER") // roles() 自动补 ROLE_ 前缀
.build();
return new InMemoryUserDetailsManager(admin);
}
}
方式三:自定义 UserDetailsService 查库(生产主流)
只须实现接口:Security 调用 loadUserByUsername 拿到用户,DaoAuthenticationProvider 再用 PasswordEncoder 比对表单密码与库中密文。
@Service
public class DbUserDetailsService implements UserDetailsService {
private final UserRepository userRepository; // 构造注入省略
@Override
public UserDetails loadUserByUsername(String username) {
User user = userRepository.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("用户不存在: " + username));
return User.withUsername(user.getUsername())
.password(user.getPassword()) // 数据库里必须存 BCrypt 密文
.roles(user.getRole()) // 如 ADMIN/USER,自动转 ROLE_ADMIN
.build();
}
}
校验流程一句话:表单提交 → UsernamePasswordAuthenticationFilter 取 username/password → DaoAuthenticationProvider 调 loadUserByUsername → passwordEncoder.matches(明文, 密文) → 成功则构造带权限的 Authentication 放进 SecurityContext;用户不存在抛 UsernameNotFoundException,最终表现为 401/403。
密码存储规范
- 明文密码是事故:务必 BCrypt(内置强度 10)或更高成本算法;
- Boot 默认的
PasswordEncoder是 DelegatingPasswordEncoder,密文带{bcrypt}前缀,将来换算法不影响存量数据; - 注册、改密接口里用同一个 encoder.encode() 加密后再入库。
认证后的使用
// 控制器参数注入
@GetMapping("/me")
public String me(@AuthenticationPrincipal UserDetails user) {
return user.getUsername(); // 输出:当前登录用户名
}
小结:认证链路的用户来源只需三选一——属性、内存、或自定义 UserDetailsService;配合 BCryptPasswordEncoder,Security 即可完成"查用户 + 验密文"的标准认证。