- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
@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;
但我得到 java.util.NoSuchElementException: No value present
。您知道我如何实现比较旧密码和新密码的逻辑吗?
编辑:我试过这个设计:
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
没有显示。
最佳答案
我认为你的代码有几个问题。
根据实际使用的编码算法,密码编码器有多种类型。如果“passwordEncoder”的类型是 MD5、SHA1 等,您很可能会遇到密码冲突,因为您希望密码是唯一的。
意味着如果一个用户有一个弱密码,例如“topSecret123”,而另一个用户有相同的密码“topSecret123”,你的方法
oldPasswordsService.findEncryptedPassword(...)
将返回多个条目,而不是一个。
这将导致例如 NonUniqueResultException
什么的。
将密码与用户名相关联。获取由 userId(或类似的东西)给出的用户,并使用该用户的密码进行密码检查。
使用例如 BCryptPasswordEncoder
.此类型 PasswordEncoder
负责给你的东西加盐。这样可以避免在您的数据库中出现可能的重复条目。如果仅提供“密码”,这些类型的密码编码器无法计算密码或检查密码是否匹配。由于他们对您的编码密码使用“salt”,因此这些类型的密码编码器需要(salt+hashed)密码作为输入,以检查提供的密码是否匹配。
代码
OldPasswords value = list.get();
是问题所在。 Optional<OldPasswords>
可能包含 null
值(value)。一个电话.get()
在 Optional
上将null
值将导致 java.util.NoSuchElementException: No value present
.
Optional<OldPasswords> list = oldPasswordsService.findEncryptedPassword(passwordEncoder.encode("new password entered form web reset form"));
if (!list.isPresent()) {
return new ResponseEntity<>("The old password value you've entered is incorrect", HttpStatus.UNAUTHORIZED);
}
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);
}
您也不必制作 @Id
专栏unique=true
, 也不 nullable=false
没有updateable=false
.
您发布的代码使用服务并更新域对象。并且它确实返回一个ResponseEntity
.您显然将应用程序的不同层合二为一。
您暴露了信息,即所选的(新)密码已被其他用户使用!不要那样做!加起来是因为第 1 点。我已经列出了。
问题更新后,我也想更新我的答案。由于更新问题中的代码片段无法编译,我想根据我从代码片段中了解到的内容制作一个非常简单的基本示例。
我不评论问题中显示的“重置密码”设计的概念,因为中间缺少很多代码。
包括测试在内的完整代码可以在这里找到:https://github.com/mschallar/so_oldpasswords_example
问题中请求的函数的代码是:
@PostMapping("reset_password")
public ResponseEntity<?> reset(@RequestBody PasswordResetDTO resetDTO) {
Optional<User> findByLogin = this.userService.findByLogin(resetDTO.getName());
if (!findByLogin.isPresent()) {
return ResponseEntity.notFound().build();
}
User user = findByLogin.get();
Integer userId = user.getUserId();
String encodedPassword = passwordEncoder.encode(resetDTO.getPassword());
for (OldPasswords oldPasswords : oldPasswordsService.findByOwnerId(userId)) {
if (passwordEncoder.matches(resetDTO.getPassword(), oldPasswords.getEncryptedPassword())) {
// Information: Don't do that! Don't reveal that another user already has such a password!
log.info("Password already used.");
return new ResponseEntity<>("PASSWORD_ALREADY_USED", HttpStatus.BAD_REQUEST);
}
}
OldPasswords oldPasswords = new OldPasswords();
oldPasswords.setEncryptedPassword(passwordEncoder.encode(encodedPassword));
oldPasswords.setPasswordOwnerId(userId);
oldPasswordsService.save(oldPasswords);
user.setEncryptedPassword(encodedPassword);
user.setResetPasswordToken(null);
userService.save(user);
return ResponseEntity.ok().build();
}
关于java - 如何使用 Spring "matches"方法检查旧密码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60626886/
Internal Server Error: /admin/account/customuser/add/ Traceback (most recent call last): File "C:\
有问题!虽然我发现几乎相似的线程但没有帮助:( 我编写了一个 php 脚本来从我的 MySQL 数据库中获取注册用户的数量。该脚本在我的本地主机上运行良好;它使用给定的用户名、密码和主机名,分别是“r
我正在做一项基于密码的作业,我将 key 和消息放在单独的数组中。我想创建第三个数组,其中包含围绕消息大小的 key ,如下所示: message keykeyk 我已经在这个问题上苦苦挣扎了一段时间
我的几个客户要求我实现图形密码检查器,例如 关于如何实现这种 UI 有什么想法吗? 最佳答案 试着看看这个:https://code.google.com/p/android-lockpattern/
我正在使用 MAMP,每次登录 phpMyAdmin 时,都会收到以下错误/警告消息: the configuration file now needs a secret passphrase (bl
我正在尝试通过将 Visual Studio 2013 连接到我的测试机来调试 WDF 驱动程序。它创建一个名为 WDKRemoteUser 的用户,并在进行测试时尝试自动登录。有人知道这个用户的密码
使用具有指定用户名和密码的 SVN 提交。我希望服务器抛出错误;所以我可以告诉我的用户他/她的密码错误。 相反,在使用错误密码提交后: svn commit "test_file.txt" --use
我正在尝试实现 friend 推荐。 它从节点“你”开始。而且,我想找到节点“安娜”。 换句话说,这是我的两个或更多 friend 共同认识的人。上面的示例节点是 Anna。 如果您的帮助,我将不胜感
我都尝试过 wget --user=myuser --password=mypassword myfile 和 wget --ftp-user=myuser --ftp-password=mypass
我的一位用户提示说,每当他尝试使用默认管理界面(Django 的管理员)添加新用户(auth.User)时,新用户名和密码都会自动填充他自己的。 问题是他在登录时要求 Firefox 记住他的用户名/
我们正在开发一款应用(当然)用于应用购买 (IAP)。我已完成指南中的所有操作以启用 iap,并且一切正常,直到我想要购买为止。 部分代码: MainViewController.m -(vo
我试图创建两个可选匹配项的并集(如下所示),但我得到的不是并集,而是两者的交集。我应该如何更改此查询以获得所需的联合? optional match (a:PA)-[r2:network*2]-(b:
我想将Ansible用作另一个Python软件的一部分。在该软件中,我有一个包含其用户名/密码的主机列表。 有没有一种方法可以将SSH连接的用户/密码传递给Ansible ad-hoc命令或以加密方式
嗨,我在使用xampp的Apache Web服务器上收到错误500。直到我使用.htaccess,.htpasswd文件,错误才出现。我搜索了,但找不到语法错误。我只有1张图片和要保护的索引文件。以下
我一直使用它来编辑用户帐户信息: $this->validate($request, [ 'password' => 'min:6', 'password_confirmation'
我需要使用InstallUtil来安装C# Windows服务。我需要设置服务登录凭据(用户名和密码)。这一切都需要默默地完成。 有没有办法做这样的事情: installutil.exe myserv
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 这个问题似乎不是关于 a specific programming problem, a software
如果我有一个随机的、16 个字符长的字母数字盐(不同大小写),它是为每个用户生成和存储的,我是否还需要一个站点范围的盐? 换句话说,这样好吗? sha1($user_salt . $password)
我正在开发一个空白程序,该程序将允许用户创建一个帐户,以便他们可以存储其余额和提款/存款。用户输入用户名和密码后,如何存储这些信息以便用户可以登录并查看其余额?我不一定要尝试使其非常安全,我只是希望能
我正在尝试寻找一种通用方法来搜索没有链接到另一个节点或节点集的节点或节点集。例如,我能够找到特定类型(例如 :Style)的所有节点,这些节点以某种方式连接到一组特定的节点(例如 :MetadataR
我是一名优秀的程序员,十分优秀!