英文:
@Pattern annotation does not work correctly because it runs when i saving the user to the database it validates the hashed password
问题
我将尝试强制用户的密码必须符合一些约束。因此,我使用@Pattern注解强制用户根据我的约束输入密码。但问题是,我从请求中将用户数据作为json发送,并且在服务类中使用哈希密码更改密码。因此,将用户保存到数据库的方式是使用哈希密码保存它。因此,@Pattern不验证实际密码,而是验证哈希密码。因为它很长并且有数字、特殊字符、小写和大写字母,它总是验证为true。你能帮我解决这个问题吗?当我将用户保存到数据库时,如果不对密码进行哈希,它就按预期工作。
这是我的用户模型
@Entity
@Getter
@Setter
public class User {
@Id
@GeneratedValue(strategy= GenerationType.AUTO,generator="native")
@GenericGenerator(name = "native",strategy = "native")
private Long userId;
private String firstname;
private String lastname;
@Pattern(regexp = EmailConstants.REGEX_PATTERN, message = EmailConstants.PATTERN_DOES_NOT_MATCH_MESSAGE)
private String username;
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
@Pattern(regexp = "^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9]).{8,}$", message = "try more secure password")
private String password;
@JsonIgnore
@OneToMany (mappedBy = "user", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private Set<Authority> authorities;
}
这是我的Auth服务类,我使用哈希密码保存用户。
@Service
@RequiredArgsConstructor
public class AuthService {
private final UserService userService;
private final EmailVerificationService emailVerificationService;
public User registerUser (User user, PasswordEncoder passwordEncoder) throws Exception {
String hashPassword = passwordEncoder.encode(user.getPassword());
user.setPassword(hashPassword);
Authority authority = new Authority();
authority.setName(SecurityConstants.ROLE_USER);
authority.setUser(user);
Set<Authority> authorities = new HashSet<>();
authorities.add(authority);
user.setAuthorities(authorities);
//emailVerificationService.verifyEmail(user.getUsername());
userService.createUser(user);
return user;
}
}
英文:
I will try to force the user their password must have some constraints. So, I use @Pattern annotation to force user to enter the password according to my constraints. But the problem is i send the user data as json from a request and in a service class i change the password with the hashed password. So, the way i saving the user to the database is saving it with the hashed password. So, @Pattern does not validate the actual password but validate the hashed password. So, because it's so long and there are numbers, special charecters, lower and upper case lettters it always validates true. Can you help me with that? When i save the user to the database without hashing the password it work as expected.
So, because it's so long and there are numbers, special charecters, lower and upper case lettters it always validates true. Can you help me with that? When i save the user to the database without hashing the password it work as expected.
Here is my User Model
@Entity
@Getter
@Setter
public class User {
@Id
@GeneratedValue(strategy= GenerationType.AUTO,generator="native")
@GenericGenerator(name = "native",strategy = "native")
private Long userId;
private String firstname;
private String lastname;
@Pattern(regexp = EmailConstants.REGEX_PATTERN, message = EmailConstants.PATTERN_DOES_NOT_MATCH_MESSAGE)
private String username;
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
@Pattern(regexp = "^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9]).{8,}$", message = "try more secure password")
private String password;
@JsonIgnore
@OneToMany (mappedBy = "user", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private Set<Authority> authorities;
}
And here is my auth Service class that i save the user with the hash password.
@Service
@RequiredArgsConstructor
public class AuthService {
private final UserService userService;
private final EmailVerificationService emailVerificationService;
public User registerUser (User user, PasswordEncoder passwordEncoder) throws Exception {
String hashPassword = passwordEncoder.encode(user.getPassword());
user.setPassword(hashPassword);
Authority authority = new Authority();
authority.setName(SecurityConstants.ROLE_USER);
authority.setUser(user);
Set<Authority> authorities = new HashSet<>();
authorities.add(authority);
user.setAuthorities(authorities);
//emailVerificationService.verifyEmail(user.getUsername());
userService.createUser(user);
return user;
}
}
答案1
得分: 2
有一个很好的想法,即为请求模型(传入的数据 - UserDto)和领域模型(内部使用的 @Entity - User)使用不同的对象。
例如,您可以将 UserDto 设计为一个简单的 Java 类,甚至是一个记录。这是用于创建用户的传入请求模型,可以验证用户名和密码。
@Value
public class UserDto {
String firstname;
String lastname;
@Pattern(regexp = EmailConstants.REGEX_PATTERN, message = EmailConstants.PATTERN_DOES_NOT_MATCH_MESSAGE)
String username;
@Pattern(regexp = "^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9]).{8,}$", message = "try more secure password")
String password;
}
然后,您可以基于此 DTO 创建一个 User 实体。例如,类似这样的实现:
public User buildUser(UserDto dto) {
User user = new User();
user.setFirstname(dto.getFirstname());
user.setLastname(dto.getLastname());
user.setUsername(dto.getUsername());
String hashPassword = passwordEncoder.encode(dto.getPassword());
user.setPassword(hashPassword);
Authority authority = new Authority();
authority.setName(SecurityConstants.ROLE_USER);
authority.setUser(user);
Set<Authority> authorities = new HashSet<>();
authorities.add(authority);
user.setAuthorities(authorities);
return user;
}
此外,由于现在关注点已分离,您的 User 类将不再需要 @JsonIgnore
(或任何其他与 JSON 相关的注解)。
P.S. 在控制器中,您需要添加 @Valid 注解。例如:
@PostMapping("users")
public void refisterUser(@Valid @RequestBody UserDto dto) {
//...
}
阅读有关 DTO 设计模式的更多信息:DTO设计模式
希望这有所帮助。
英文:
it is a good idea to have different objects for the request model (the data coming in - UserDto) and your domain model (the @Entity you use internally - User).
For example, you can have a UserDto as a simple java class or even a record. This is the request model coming in for creating a user and it can be validated for username and password.
@Value
public class UserDto {
String firstname;
String lastname;
@Pattern(regexp = EmailConstants.REGEX_PATTERN, message = EmailConstants.PATTERN_DOES_NOT_MATCH_MESSAGE)
String username;
@Pattern(regexp = "^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9]).{8,}$", message = "try more secure password")
String password;
}
Then, you can create a User entity based on this DTO. For example, something like this:
public User buildUser(UserDto dto) {
User user = new User();
user.setFirstname(dto.getFirstname());
user.setLastname(dto.getLastname());
user.setUsername(dto.getUsername());
String hashPassword = passwordEncoder.encode(dto.getPassword());
user.setPassword(hashPassword);
Authority authority = new Authority();
authority.setName(SecurityConstants.ROLE_USER);
authority.setUser(user);
Set<Authority> authorities = new HashSet<>();
authorities.add(authority);
user.setAuthorities(authorities);
return user;
}
Additionally, your User class will no longer need the @JsonIgnore
(or any other json-related annotations) because now you have spilt the concerns, UserDto will manage the presentation of the class while User will handle the persistence.
PS: in the controller, you will need to add the @Valid annotation. for example:
@PostMapping("users")
public void refisterUser(@Valid @RequestBody UserDto dto) {
//...
}
Read more about the DTO design pattern here: https://www.baeldung.com/java-dto-pattern
hope this helps.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论