作者:Eugen Paraschiv
转载自公众号:stackgc
1、概述
本文将讨论注册流程中的一个关键部分 —— 密码编码(以非明文方式存储密码)。
Spring Security 支持部分编码机制 —— 本文将使用 BCrypt 编码方式,它通常被认为是密码编码的最佳解决方案。
大多数其他机制,如 MD5PasswordEncoder 和 ShaPasswordEncoder 使用了较弱的编码算法,现在已被弃用了。
2、定义密码编码器
我们首先在配置中将 BCryptPasswordEncoder 定义为一个 bean:
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
一些旧的实现方式,比如 SHAPasswordEncoder,会要求客户端在编码密码时传入一个 salt 值(又称盐值)。
然而 BCrypt 方式不同,它会在内部产生一个随机盐值。这很重要,因为这意味着每次调用都会有不同的结果,因此我们只需要对密码进行一次编码。
另外请注意,BCrypt 算法会生成一个长度为 60 的字符串,因此我们需要确保存储密码的列有足够的空间。常见的一个错误是创建一个长度不足的列,然后在验证时得到一个无效的用户名或密码错误。
3、在注册时编码密码
在用户注册流程中,我们使用 UserService 中的 PasswordEncoder 对密码进行散列处理:
示例 3.1 — UserService 对密码散列处理
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public User registerNewUserAccount(UserDto accountDto) throws EmailExistsException {
if (emailExist(accountDto.getEmail())) {
throw new EmailExistsException(
"There is an account with that email adress:" + accountDto.getEmail());
}
User user = new User();
user.setFirstName(accountDto.getFirstName());
user.setLastName(accountDto.getLastName());
user.setPassword(passwordEncoder.encode(accountDto.getPassword()));
user.setEmail(accountDto.getEmail());
user.setRole(new Role(Integer.valueOf(1), user));
return repository.save(user);
}
4、在认证时编码密码
让我们来处理这个流程的另一部分,在用户认证时对密码进行编码。
首先,我们需要将之前定义的密码编码器 bean 注入到身份验证提供器中:
@Autowired
private UserDetailsService userDetailsService;
@Bean
public DaoAuthenticationProvider authProvider() {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(userDetailsService);
authProvider.setPasswordEncoder(encoder());
return authProvider;
}
security 配置很简单:
- 注入 UserDetailsService 实现类
- 定义一个认证提供器,引用了 UserDetailsService
- 启用密码编码器
最后,我们需要在 security XML 配置中引用这个认证提供器:
<authentication-manager>
<authentication-provider ref="authProvider" />
</authentication-manager>
或者,您也可以使用 Java 配置:
@Configuration
@ComponentScan(basePackages = { "org.baeldung.security" })
@EnableWebSecurity
public class SecSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authProvider());
}
...
}
5、结论
本教程继上一篇的注册流程,通过利用简单却非常强大的 BCrypt 实现来对密码进行编码并存储到数据库中。
该注册流程在 Spring Security 教程中已经完全实现,您可以在 GitHub 项目中找到。