Проверка пользовательского пароля в Angular 5 - PullRequest
0 голосов
/ 27 августа 2018

Я пытаюсь добавить пользовательскую проверку пароля в поле пароля. Пароль должен содержать не менее 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]);
  }
}

Ответы [ 3 ]

0 голосов
/ 27 августа 2018

Демонстрация Stackblitz

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])]
});

пароль-strength.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.'
}
* *} Тысяча двадцать-один
}
0 голосов
/ 27 августа 2018

Я поэкспериментировал с этим, чтобы посмотреть, смогу ли я понять, как использовать Валидаторы в 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 { }
0 голосов
/ 27 августа 2018

Вы передаете 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>
...