在这篇文章中,我们将通过一个示例详细了解密码编码器。传统上,存储密码很困难。应用程序必须对用户密码进行编码并将其存储在数据库中。
但是使用 spring security 提供的密码编码器,所有这些都可以自动完成。密码编码器是将纯文本密码转换为哈希的 bean。由于哈希值无法反转为明文,因此它是一种安全的密码存储方式。
首先,散列算法采用一系列字节并将其转换为唯一的固定长度散列字符串。
散列算法是单向函数,不能反转。意味着无法从散列中生成原始文本。
此特征可以使用散列存储密码。
对于密码编码/散列,Spring Security 需要一个密码编码器实现。此外,它还提供基于行业标准的实现。这些编码器将用于密码存储阶段和身份验证的验证阶段。
passwordEncoders 有两个重要任务。
encoder.encode(String rawPassword)
- 将给定的明文密码转换为编码密码。它如何转换取决于实现。这部分发生在密码存储在数据库中时。通常在注册用户或更改密码时。encoder.matches(rawPassword, encodedPassword)
- 在登录时使用。安全上下文将从数据库中加载加密密码,并使用此方法与原始密码进行比较。以下是编码器在注册过程中的实现。
下图说明了 Spring Security 如何使用编码器来验证登录密码。
现在让我们看一些例子。
在注册时,您需要对密码进行编码,然后再将其存储到数据库中。为此,您需要定义一个类型为 PasswordEncoder
的 bean。
@Bean
PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
Code language: JavaScript (javascript)
在你的注册 API的地方,你必须自动装配这个 bean。如下
@RestController
public class RegistrationController {
private final UserAccountRepository userAccountRepository;
private final PasswordEncoder passwordEncoder;
public UserController(UserAccountRepository userAccountRepository, PasswordEncoder passwordEncoder) {
this.userAccountRepository = userAccountRepository;
this.passwordEncoder = passwordEncoder;
}
@PostMapping("/register")
public UserAccount register(@RequestParam("username") String username, @RequestParam("password") String password, @RequestParam("firstName") String firstName, @RequestParam("lastName") String lastName) {
UserAccount userAccount = new UserAccount();
userAccount.setFirstName(firstName);
userAccount.setLastName(lastName);
userAccount.setUsername(username);
userAccount.setActive(true);
userAccount.setPassword(passwordEncoder.encode(password));
return userAccountRepository.save(userAccount);
}
}
Code language: PHP (php)
您可以在本文末尾查看 git 存储库以获取完整实现。在此示例中,我们在 BCryptPasswordEncoder 的帮助下注册了用户。您可以在下图中看到密码是如何编码的。
如果您是从 spring security4 升级,那么您需要确保当前密码使用相同的算法进行加密。这是将明文密码转换为哈希的示例代码。
public class BCryptConverter {
public static void main(String[] args) {
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
System.out.println(bCryptPasswordEncoder.encode("[email protected]"));
System.out.println(bCryptPasswordEncoder.encode("Hello#123"));
}
}
Code language: JavaScript (javascript)
如果您想在同一个数据源中使用多种类型的编码器,可能会出现这种情况。例如,MD5、SHA-256、pbkdf2 是一些常见的密码散列函数。出于这个原因,spring 提供了一个 DelegatingPasswordEncoder
。
此编码器通过基于密码前缀路由请求来依赖其他密码编码器。要使用它,您需要对我们之前的代码进行一些更改。
您需要为类型 DelegatingPasswordEncoder
而不是 BCryptPasswordEncoder
创建 bean,您可以在 PasswordEncoderFactories
类的帮助下轻松完成此操作。
@Bean
PasswordEncoder passwordEncoder(){
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
Code language: CSS (css)
默认情况下,此委托编码器使用 bcrypt 算法进行编码。这就是为什么存储在数据库中的密码会在前面加上文本 {bcrypt}
。当调用 encoder.matches()
方法时,此附加信息将用于识别适当的 passwordEncoder。
编码类型的默认映射如下所示。
编码 | 实现匹配 |
---|---|
bcrypt | new org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder(); |
ldap | new org.springframework.security.crypto.password.LdapShaPasswordEncoder(); |
MD4 | new org.springframework.security.crypto.password.Md4PasswordEncoder(); |
MD5 | new org.springframework.security.crypto.password.MessageDigestPasswordEncoder(“MD5”); |
noop | new org.springframework.security.crypto.password.NoOpPasswordEncoder.getInstance(); |
pbkdf2 | new org.springframework.security.crypto.password.Pbkdf2PasswordEncoder(); |
scrypt | new org.springframework.security.crypto.scrypt.SCryptPasswordEncoder(); |
SHA-1 | new org.springframework.security.crypto.password.MessageDigestPasswordEncoder(“SHA-1”); |
SHA-256 | new org.springframework.security.crypto.password.MessageDigestPasswordEncoder(“SHA-256”); |
sha256 | new org.springframework.security.crypto.password.StandardPasswordEncoder(); |
argon2 | new org.springframework.security.crypto.argon2.Argon2PasswordEncoder(); |
您可以通过自己创建 DelegatingPasswordEncoder 来自定义支持的编码类型列表。如下所示
@Bean
PasswordEncoder passwordEncoder() {
Map<String, PasswordEncoder> encoders = new HashMap<>();
encoders.put("noop", NoOpPasswordEncoder.getInstance());
encoders.put("bcrypt", new BCryptPasswordEncoder());
encoders.put("MD5", new MessageDigestPasswordEncoder("MD5"));
return new DelegatingPasswordEncoder("bcrypt", encoders);
}
Code language: JavaScript (javascript)
委托编码器将允许编码密码和纯文本密码共存。 但是,那些未编码的密码仍然存在安全风险。 在这些情况下,编写一个程序,将所有纯文本密码转换为编码字符串。 示例如下
public class BCryptConvert {
public static void main(String[] args) {
PasswordEncoder passwordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
System.out.println(passwordEncoder.encode("[email protected]"));
System.out.println(passwordEncoder.encode("Hello#123"));
}
}
Code language: JavaScript (javascript)
您可以在GitHub repository 找到这些示例。
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://springhow.com/spring-security-password-encoder/
内容来源于网络,如有侵权,请联系作者删除!