许多在线网络平台要求用户在注册时输入强密码。此策略有助于减少用户数据对任何黑客攻击的脆弱性。
在本文中,我们将创建一个带有注册页面的简单表单。在继续本教程之前,您应该对使用 Spring 框架的 Java 有基本的了解。
Passay是一个基于Java的密码生成和验证库。它建立在成功的基础上,并提供了一个全面且可扩展的功能集。vt-password
使用 Spring Initializr 生成具有以下依赖项的 Spring boot 2 项目:web、lombok、spring-boot-starter-validation。
然后添加 Passay 依赖项以管理验证策略。
- <dependency>
- <groupId>org.passaygroupId>
- <artifactId>passayartifactId>
- <version>1.6.0version>
- dependency>
您可以在此处找到所有版本。
使用包含要验证的信息的类。UserData
- package com.passay.sample.custompasswordvalidation.model;
-
- import com.passay.sample.custompasswordvalidation.annotation.PasswordValueMatch;
- import com.passay.sample.custompasswordvalidation.annotation.ValidPassword;
- import lombok.*;
-
- import javax.validation.constraints.Email;
- import javax.validation.constraints.NotBlank;
- import javax.validation.constraints.NotEmpty;
- import javax.validation.constraints.NotNull;
-
- /**
- *
UserData
- *
- * @author aek
- */
- @PasswordValueMatch.List({
- @PasswordValueMatch(
- field = "password",
- fieldMatch = "confirmPassword",
- message = "Passwords do not match!"
- )
- })
- @AllArgsConstructor
- @NoArgsConstructor
- @Getter
- @Setter
- @ToString
- public class UserData {
-
-
- @NonNull
- @NotBlank(message = "username is mandatory")
- private String username;
-
- @NotNull
- @NotEmpty
- @Email
- private String email;
-
-
- @ValidPassword
- @NonNull
- @NotBlank(message = "New password is mandatory")
- private String password;
-
-
- @ValidPassword
- @NonNull
- @NotBlank(message = "Confirm Password is mandatory")
- private String confirmPassword;
- }
-
-
两个重要的注释:
@PasswordValueMatch:检查密码和确认密码是否匹配。@ValidPassword:包含密码验证策略。密码验证涉及从规则集创建 a,它只是一个对象列表。注释是由PasswordValidatorRule@ValidPasswordPasswordConstraintValidator.class
- package com.passay.sample.custompasswordvalidation.annotation;
-
-
-
- import com.passay.sample.custompasswordvalidation.utils.PasswordConstraintValidator;
-
- import javax.validation.Constraint;
- import javax.validation.Payload;
- import java.lang.annotation.Documented;
- import java.lang.annotation.Retention;
- import java.lang.annotation.Target;
-
- import static java.lang.annotation.ElementType.*;
- import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-
- /**
- *
ValidPassword
- *
- * @author aek
- */
- @Documented
- @Constraint(validatedBy = PasswordConstraintValidator.class)
- @Target({ TYPE, FIELD, ANNOTATION_TYPE })
- @Retention(RUNTIME)
- public @interface ValidPassword {
-
- String message() default "Invalid Password";
-
- Class>[] groups() default {};
-
- Class extends Payload>[] payload() default {};
- }
请考虑以下简单密码策略:
该类包含所有以前定义的密码规则,而无需手动实现它们。PasswordConstraintValidator
- package com.passay.sample.custompasswordvalidation.utils;
-
- import com.passay.sample.custompasswordvalidation.annotation.ValidPassword;
- import lombok.SneakyThrows;
- import org.passay.*;
-
- import javax.validation.ConstraintValidator;
- import javax.validation.ConstraintValidatorContext;
- import java.io.InputStream;
- import java.util.Arrays;
- import java.util.List;
- import java.util.Properties;
-
-
- /**
- *
PasswordConstraintValidator
- *
- * @author aek
- */
- public class PasswordConstraintValidator implements ConstraintValidator
{ -
- @Override
- public void initialize(final ValidPassword arg0) {
-
- }
-
- @SneakyThrows
- @Override
- public boolean isValid(String password, ConstraintValidatorContext context) {
-
- //customizing validation messages
- Properties props = new Properties();
- InputStream inputStream = getClass()
- .getClassLoader().getResourceAsStream("passay.properties");
- props.load(inputStream);
- MessageResolver resolver = new PropertiesMessageResolver(props);
-
- PasswordValidator validator = new PasswordValidator(resolver, Arrays.asList(
-
- // length between 8 and 16 characters
- new LengthRule(8, 16),
-
- // at least one upper-case character
- new CharacterRule(EnglishCharacterData.UpperCase, 1),
-
- // at least one lower-case character
- new CharacterRule(EnglishCharacterData.LowerCase, 1),
-
- // at least one digit character
- new CharacterRule(EnglishCharacterData.Digit, 1),
-
- // at least one symbol (special character)
- new CharacterRule(EnglishCharacterData.Special, 1),
-
- // no whitespace
- new WhitespaceRule(),
-
- // rejects passwords that contain a sequence of >= 5 characters alphabetical (e.g. abcdef)
- new IllegalSequenceRule(EnglishSequenceData.Alphabetical, 5, false),
- // rejects passwords that contain a sequence of >= 5 characters numerical (e.g. 12345)
- new IllegalSequenceRule(EnglishSequenceData.Numerical, 5, false)
- ));
-
- RuleResult result = validator.validate(new PasswordData(password));
-
- if (result.isValid()) {
- return true;
- }
-
- List
messages = validator.getMessages(result); - String messageTemplate = String.join(",", messages);
- context.buildConstraintViolationWithTemplate(messageTemplate)
- .addConstraintViolation()
- .disableDefaultConstraintViolation();
- return false;
- }
-
- }
Passay 列出了几个规则来帮助验证密码。可以使用Passay编写的规则的完整列表可以在官方网站上找到。
除了密码验证之外,passay 还允许您使用给定的策略生成密码。
创建以捕获将为数据验证引发的所有异常。BaseExceptionHandler.class
- package com.passay.sample.custompasswordvalidation.web;
-
- import lombok.extern.slf4j.Slf4j;
- import org.springframework.http.HttpStatus;
- import org.springframework.web.bind.MethodArgumentNotValidException;
- import org.springframework.web.bind.annotation.ExceptionHandler;
- import org.springframework.web.bind.annotation.ResponseStatus;
- import org.springframework.web.bind.annotation.RestControllerAdvice;
-
- import java.util.HashMap;
- import java.util.Map;
-
- @Slf4j
- @RestControllerAdvice
- public class BaseExceptionHandler {
-
-
- @ResponseStatus(HttpStatus.BAD_REQUEST)
- @ExceptionHandler(MethodArgumentNotValidException.class)
- public ApiResponse handleValidationExceptions(MethodArgumentNotValidException ex) {
-
- Map
errors = new HashMap<>(); -
- ex.getBindingResult().getFieldErrors().forEach(error -> {
- if (errors.containsKey(error.getField())) {
- errors.put(error.getField(), String.format("%s, %s", errors.get(error.getField()), error.getDefaultMessage()));
- } else {
- errors.put(error.getField(), error.getDefaultMessage());
- }
- }
- );
- return new ApiResponse(errors, "VALIDATION_FAILED");
- }
- }
启动后端项目。http://localhost:8080/
在本文中,我创建了一个使用Angular作为前端的注册表单。
现在,使用命令行在文件夹下添加 Angular 项目:src/main
ng new webapp
添加注册表单代码的内容后。运行前端npm start
打开浏览器并输入无效的密码以验证验证是否正常工作。http://localhost:4200/

完整的源代码可以在我的GitHub 存储库中找到。