java如何使用Spring“匹配”方法检查旧密码?
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private OldPasswordsService oldPasswordsService;
Optional<OldPasswords> list = oldPasswordsService.findEncryptedPassword(passwordEncoder.encode("new password entered form web reset form"));
OldPasswords value = list.get();
boolean matches = passwordEncoder.matches("new password entered form web reset form", value.getEncryptedPassword());
if (matches)
{
return new ResponseEntity<>("PASSWORD_ALREADY_USED", HttpStatus.BAD_REQUEST);
}
else
{
OldPasswords oldPasswords = new OldPasswords();
oldPasswords.setEncryptedPassword(passwordEncoder.encode(resetDTO.getPassword()));
oldPasswordsService.save(oldPasswords);
}
旧密码表:
@Table(name = "old_passwords")
public class OldPasswords implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", unique = true, updatable = false, nullable = false)
private int id;
@Column(name = "encrypted_password", length = 255)
private String encryptedPassword;
@Column(name = "password_owner_id", length = 4)
private Integer passwordOwnerId;
@Column(name = "created_at")
@Convert(converter = LocalDateTimeConverter.class)
private LocalDateTime createdAt;
但我明白了。 你知道我如何实现一个比较新旧密码的逻辑吗
编辑: 我试过这个设计:
SQL查询:
public List<OldPasswords> findByOwnerId(Integer ownerId) {
String hql = "select e from " + OldPasswords.class.getName() + " e where e.passwordOwnerId = :passwordOwnerId ORDER BY e.createdAt DESC";
TypedQuery<OldPasswords> query = entityManager.createQuery(hql, OldPasswords.class).setMaxResults(3).setParameter("passwordOwnerId", ownerId);
List<OldPasswords> list = query.getResultList();
return list;
}
终点:
@PostMapping("reset_password")
public ResponseEntity<?> reset(@RequestBody PasswordResetDTO resetDTO) {
return this.userService.findByLogin(resetDTO.getName()).map(user -> {
Integer userId = user.getId();
List<OldPasswords> list = oldPasswordsService.findByOwnerId(userId);
if(!list.isEmpty() && !list.isEmpty()) {
for (int i = 0; i<list.size(); i++){
OldPasswords value = list.get(i);
boolean matches = passwordEncoder.matches(resetDTO.getPassword(), value.getEncryptedPassword());
if (matches) {
return new ResponseEntity<>("PASSWORD_ALREADY_USED", HttpStatus.BAD_REQUEST);
}
}
}
OldPasswords oldPasswords = new OldPasswords();
oldPasswords.setEncryptedPassword(passwordEncoder.encode(resetDTO.getPassword()));
oldPasswords.setPasswordOwnerId(userId);
oldPasswordsService.save(oldPasswords);
user.setEncryptedPassword(passwordEncoder.encode(resetDTO.getPassword()));
user.setResetPasswordToken(null);
userService.save(user);
return ok().build();
}).orElseGet(() -> notFound().build());
}
但是,当我使用相同的密码多次更改代码时,错误PASSWORD_ALREADY_USED
不会显示
# 1 楼答案
我用一个简单的解决方案解决了这个问题
newPassword
和oldPassword
必须在字符串中,以便它匹配两个密码# 2 楼答案
检查可选类型列表是否包含有效的必需值
或者像@Manuel建议的那样
# 3 楼答案
我认为你的代码有几个问题
一,。“passwordEncoder”的类型
根据实际使用的编码算法,有不同类型的密码编码器。 如果“passwordEncoder”的类型为MD5、SHA1,则很可能会发生密码冲突,因为您希望密码是唯一的
意味着如果一个用户有一个弱密码,例如“topSecret123”,而另一个用户有相同的密码“topSecret123”,您可以使用该方法
将返回多个条目,而不是一个
这将导致
NonUniqueResultException
或其他事情1.1可能的解决方案:
将密码与用户名关联。获取用户ID(或类似信息)提供的用户,并使用该用户的密码进行密码检查
1.2另一种可能的解决方案
使用一个例如
BCryptPasswordEncoder
。这种类型的PasswordEncoder
负责向你的has中添加盐。这避免了数据库中可能存在的重复条目。 如果只提供“密码”,这些类型的密码编码器无法计算密码或检查密码是否匹配。由于这些类型的密码编码器将“salt”与您的编码密码一起使用,因此需要(salt+散列)密码作为输入,以检查提供的密码是否匹配二,。实际问题
密码
这就是问题所在。
Optional<OldPasswords>
可以包含null
值。 对Optional
值的.get()
调用null
将导致java.util.NoSuchElementException: No value present
三,。旧密码实体
您既不必使
@Id
列unique=true
,也不必使nullable=false
不updateable=false
四,。混合层
您发布的代码使用服务并更新域对象。 和它确实返回
ResponseEntity
。显然,您可以将应用程序的不同层混合到一个应用程序中五,。公开信息
您公开了所选(新)密码已被其他用户使用的信息!别那么做!这是因为第一点。我已经列出了
编辑:
问题更新后,我也想更新我的答案。 由于更新后的问题中截取的代码无法编译,我想根据我从代码片段中了解到的内容,制作一个非常简单、基本的示例
我不评论问题中显示的“重置密码”设计的概念,因为在这两者之间缺少很多代码
包括测试在内的整个代码可以在这里找到:https://github.com/mschallar/so_oldpasswords_example
问题中要求的功能代码为: