【问题标题】:Custom Password Validation in Angular 5Angular 5 中的自定义密码验证
【发布时间】:2018-08-27 16:30:04
【问题描述】:

我正在尝试将自定义密码验证添加到密码字段。密码必须至少包含 8 个字符,并且至少满足以下两个条件,但不必满足所有四个条件:

  • 有数字
  • 有小写字母
  • 有大写字母
  • 有特殊字符

我已经完成了部分验证工作,但遇到了一个问题,如果密码长度超过 8 个字符但不满足上述至少两个条件,则错误消息将显示。仅当密码少于 8 个字符时才会显示有关字符的错误。

我已经对 SO 进行了搜索,但没有成功实施类似问题的答案。我怀疑我遇到的问题与我的自定义验证函数没有与 ngModel 中的密码相关联有关。

问题:当密码长度超过 8 个字符但不符合上述字符要求时,如何在表单字段中显示错误消息?

这是相关的代码。

来自 user-form.html

 <mat-form-field *ngIf="newPassword" fxFlex="100%">
  <input matInput #password="ngModel" placeholder="Password" type="password" autocomplete="password"
         [(ngModel)]="model.password" name="password" minlength="8" (keyup)="validatePassword(model.password)" required>
  <mat-error *ngIf="invalidPassword">
    Password must contain at least two of the following: numbers, lowercase letters, uppercase letters, or special characters.
  </mat-error>
  <mat-error *ngIf="password.invalid && (password.dirty || password.touched)">
    <div *ngIf="password.errors.required">
      Password is required
    </div>
    <div *ngIf="password.errors.minlength">
      Password must be at least 8 characters
    </div>
  </mat-error>
</mat-form-field>

来自 user-form.component.ts

export class UserFormComponent implements OnInit {


  @Input()
  user: User;

  public model: any;
  public invalidPassword: boolean;


  constructor() {}

  ngOnInit() {
    this.model = this.user;
  }


  passwordFails(checks: boolean[]): boolean {
     let counter = 0;
    for (let i = 0; i < checks.length; i++) {
      if (checks[i]) {
        counter += 1;
      }
    }
    return counter < 2;
 }


  validatePassword(password: string) {
    let hasLower = false;
    let hasUpper = false;
    let hasNum = false;
    let hasSpecial = false;

    const lowercaseRegex = new RegExp("(?=.*[a-z])");// has at least one lower case letter
    if (lowercaseRegex.test(password)) {
      hasLower = true;
    }

    const uppercaseRegex = new RegExp("(?=.*[A-Z])"); //has at least one upper case letter
    if (uppercaseRegex.test(password)) {
      hasUpper = true;
    }

    const numRegex = new RegExp("(?=.*\\d)"); // has at least one number
    if (numRegex.test(password)) {
      hasNum = true;
    }

    const specialcharRegex = new RegExp("[!@#$%^&*(),.?\":{}|<>]");
    if (specialcharRegex.test(password)) {
      hasSpecial = true;
    }

    this.invalidPassword = this.passwordFails([hasLower, hasUpper, hasNum, hasSpecial]);
  }
}

【问题讨论】:

    标签: angular typescript angular-material password-protection


    【解决方案1】:

    Stackblitz Demo

    Component.html

    <div class="error-text" *ngIf="myForms.get('password').hasError('passwordStrength')">
        {{myForms.get('password').errors['passwordStrength']}}
    </div>
    

    Component.ts

    this.myForms = fb.group({
          password: [null, Validators.compose([
            Validators.required, Validators.minLength(8), PasswordStrengthValidator])]
    });
    

    密码强度.validators.ts

    import { AbstractControl, ValidationErrors } from "@angular/forms"
    
    export const PasswordStrengthValidator = function (control: AbstractControl): ValidationErrors | null {
    
    
    let value: string = control.value || '';
      let msg="";
      if (!value) {
        return null
      }
    
      let upperCaseCharacters = /[A-Z]+/g;
      let lowerCaseCharacters = /[a-z]+/g;
      let numberCharacters = /[0-9]+/g;
      let specialCharacters = /[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]+/;
      if (upperCaseCharacters.test(value) === false || lowerCaseCharacters.test(value) === false || numberCharacters.test(value) === false || specialCharacters.test(value) === false) {
    return {
      passwordStrength: 'Password must contain at least two of the following: numbers, lowercase letters, uppercase letters, or special characters.'
    }
    

    }

    }
    

    【讨论】:

      【解决方案2】:

      您正在将 boolean 值传递给 passwordFails 函数

      this.invalidPassword = this.passwordFails([hasLower, hasUpper, hasNum, hasSpecial]);
      

      将您的函数更改为以下,如果密码在其中一个条件下失败,它将返回 true。

      passwordFails(checks: boolean[]): boolean {
         return checks.filter((x)=> typeof x === 'boolean' && x === true).length > 2
      }
      

      并且在 dom 中你可以添加另一个条件来检查 invalidPassword

       <mat-form-field *ngIf="newPassword" fxFlex="100%">
        <input matInput #password="ngModel" placeholder="Password" type="password" autocomplete="password"
               [(ngModel)]="model.password" name="password" minlength="8" (keyup)="validatePassword(model.password)" required>
        <mat-error *ngIf="invalidPassword">
          Password must contain at least two of the following: numbers, lowercase letters, uppercase letters, or special characters.
        </mat-error>
        <mat-error *ngIf="password.invalid && (password.dirty || password.touched)">
          <div *ngIf="password.errors.required">
            Password is required
          </div>
          <div *ngIf="password.errors.minlength">
            Password must be at least 8 characters
          </div>
          <div *ngIf="!invalidPassword">
            Password must meet the following criteria.
          </div>
        </mat-error>
      </mat-form-field>
      

      【讨论】:

      • 我尝试更新 passwordFails 函数,但我认为这不符合我的标准 - 密码只需满足两个字符标准,而不是全部。与更新版本一样,我认为它只是检查是否满足其中一个标准。例如,当我有一个空密码字段时,它会显示条件错误。但是当我输入 1 时,该错误消息就消失了。
      • @vox:检查我更新的编辑,如果有帮助请告诉我。
      • 好的,很酷,当我将 > 2 切换为 > 1 时,它最终工作了。谢谢!
      【解决方案3】:

      我进一步尝试了这个,看看我是否可以弄清楚如何在 Angular 中使用验证器。我终于能够通过这些更新做到这一点:

      创建password-validator.directive.ts

      import { Directive, forwardRef, Attribute} from "@angular/core";
      import { Validator, AbstractControl, NG_VALIDATORS} from "@angular/forms";
      
      @Directive({
        selector: '[validatePassword]',
        providers: [
          { provide: NG_VALIDATORS, useExisting: forwardRef(() => PasswordValidator), multi: true}
        ]
      })
      
      export class PasswordValidator implements Validator {
        constructor (
          @Attribute('validatePassword')
          public invalidPassword: boolean
        ) {}
      
        validate(ctrl: AbstractControl): {[key: string]: any} {
          let password = ctrl.value;
      
          let hasLower = false;
          let hasUpper = false;
          let hasNum = false;
          let hasSpecial = false;
      
          const lowercaseRegex = new RegExp("(?=.*[a-z])");// has at least one lower case letter
          if (lowercaseRegex.test(password)) {
            hasLower = true;
          }
      
          const uppercaseRegex = new RegExp("(?=.*[A-Z])"); //has at least one upper case letter
          if (uppercaseRegex.test(password)) {
            hasUpper = true;
          }
      
          const numRegex = new RegExp("(?=.*\\d)"); // has at least one number
          if (numRegex.test(password)) {
            hasNum = true;
          }
      
          const specialcharRegex = new RegExp("[!@#$%^&*(),.?\":{}|<>]");
          if (specialcharRegex.test(password)) {
            hasSpecial = true;
          }
      
          let counter = 0;
          let checks = [hasLower, hasUpper, hasNum, hasSpecial];
          for (let i = 0; i < checks.length; i++) {
            if (checks[i]) {
              counter += 1;
            }
          }
      
          if (counter < 2) {
            return { invalidPassword: true }
          } else {
            return null;
          }
      
      
      
        }
      
      }
      

      user-form.component.html中的更新:

      <mat-form-field *ngIf="newPassword" fxFlex="100%">
        <input matInput #password="ngModel" placeholder="Password" type="password" autocomplete="password"
               [(ngModel)]="model.password" name="password" minlength="8" validatePassword="password" required>
        <mat-error *ngIf="password.invalid && (password.dirty || password.touched)">
          <div *ngIf="password.errors.invalidPassword">
            Password must have two of the four: lowercase letters, uppercase letters, numbers, and special characters
          </div>
          <div *ngIf="password.errors.required">
            Password is required
          </div>
          <div *ngIf="password.errors.minlength">
            Password must be at least 8 characters
          </div>
        </mat-error>
      </mat-form-field>
      

      user-form.module.ts中的更新:

      import {PasswordValidator} from "../password-validator.directive"; //imported to modules
      
      @NgModule({
        imports: [
          //some modules
        ],
        declarations: [
          // some modules
          PasswordValidator // added this to declarations
        ],
        exports: [
          // stuff
        ],
        providers: [
          //stuff
        ]
      })
      export class UserFormModule { }
      

      【讨论】:

        猜你喜欢
        • 2018-11-16
        • 2015-01-22
        • 1970-01-01
        • 2015-06-16
        • 1970-01-01
        • 2023-03-28
        • 2023-03-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多