密码哈希
Laravel 用
Hash::make()/Hash::check(),默认 bcrypt;Spring Security 用PasswordEncoder,默认BCryptPasswordEncoder。接口一致,只有一个要点:永远不要自己实现加密,用 BCrypt 这类自适应哈希。
基本用法
java
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
PasswordEncoder encoder = new BCryptPasswordEncoder();
String hash = encoder.encode("myPassword123"); // 加密(Hash::make)
boolean ok = encoder.matches("myPassword123", hash); // 校验(Hash::check)TIP
Spring Security 有一个神器的 DelegatingPasswordEncoder:同一个字段可以兼容不同算法(旧数据用 MD5,新数据用 bcrypt),默认格式 {bcrypt}$2a$10$...。所以看 Spring 的密码存储有时带 {bcrypt} 前缀,这是故意的,别删。
注册时存哈希
java
@Service
public class UserService {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder) {
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
}
public User register(RegisterRequest req) {
User user = new User();
user.setUsername(req.getUsername());
user.setPassword(passwordEncoder.encode(req.getPassword())); // 只存哈希
return userRepository.save(user);
}
public boolean verify(String username, String rawPassword) {
return userRepository.findByUsername(username)
.map(u -> passwordEncoder.matches(rawPassword, u.getPassword())) // Hash::check
.orElse(false);
}
}为什么不建议自己写加密
- MD5/SHA1:几十年前的算法,GPU 爆破以秒计
- 自己发明算法:几乎必然有漏洞
- 普通 SHA-256:无盐可加盐,但快,适合暴力破解
正确选择(和 Laravel 官方建议一致):
| 算法 | 用途 |
|---|---|
| BCrypt(默认) | 存密码,首选 |
Argon2(Argon2PasswordEncoder) | 更强,新项目可考虑 |
| PBKDF2 | 遗留兼容 |
BCrypt 的「成本因子」strength 默认 10,可调:
java
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(12); // 强度越高越慢越安全
}为什么 BCrypt 慢是好事?
BCrypt 故意设计成「计算慢」(约 100ms 一次),让暴力破解成本成指数上升。Laravel 的 Hash::make 默认 bcrypt 同理。加密库的「慢」是特性,不是性能缺陷。但注意别在循环里对每个用户跑 encode,会很卡。
密码校验流程(认证时的标准操作)
用户提交明文密码
→ 查库拿哈希
→ passwordEncoder.matches(明文, 哈希) // 比对
→ 返回 true/false在 认证 的 JWT 例子里,authManager.authenticate() 内部就是走这条流程,PasswordEncoder 就配置在容器里,自动参与。