使用“类验证器”在TypeScript中确认密码

lskq00tm  于 2022-12-24  发布在  TypeScript
关注(0)|答案(6)|浏览(149)

今天,我想弄清楚如何在应用程序的后端(NestJS)验证注册表单。我只是想知道是否存在一种方法来验证passwordpasswordConfirm匹配,使用class-validator包来构建一个自定义验证器或利用提供的验证器。我在考虑类验证器,而不是字段验证器。

// Maybe validator here
export class SignUpDto {
    @IsString()
    @MinLength(4)
    @MaxLength(20)
    username: string;

    @IsString()
    @MinLength(4)
    @MaxLength(20)
    @Matches(/((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$/, {message: 'password too weak'})
    password: string;

    @IsString()
    @MinLength(4)
    @MaxLength(20)
    passwordConfirm: string;
}

你有什么建议?

r1zhe5dt

r1zhe5dt1#

最后我设法解决了密码匹配的问题感谢建议@ChristopheGeers在我的问题的评论:
@piero:如前所述,它还不受支持,但这里有一个示例装饰器(@IsLongerThan):LINK....它检查一个属性是否比另一个属性长。因此,可以将一个属性与另一个属性进行比较。您可以使用此示例创建一个装饰器来完成所需的工作。
以下是我提出的解决方案:

注册日期至ts

export class SignUpDto {
    @IsString()
    @MinLength(4)
    @MaxLength(20)
    username: string;

    @IsString()
    @MinLength(4)
    @MaxLength(20)
    @Matches(/((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$/, {message: 'password too weak'})
    password: string;

    @IsString()
    @MinLength(4)
    @MaxLength(20)
    @Match('password')
    passwordConfirm: string;
}

匹配.装饰器.ts

import {registerDecorator, ValidationArguments, ValidationOptions, ValidatorConstraint, ValidatorConstraintInterface} from 'class-validator';

export function Match(property: string, validationOptions?: ValidationOptions) {
    return (object: any, propertyName: string) => {
        registerDecorator({
            target: object.constructor,
            propertyName,
            options: validationOptions,
            constraints: [property],
            validator: MatchConstraint,
        });
    };
}

@ValidatorConstraint({name: 'Match'})
export class MatchConstraint implements ValidatorConstraintInterface {

    validate(value: any, args: ValidationArguments) {
        const [relatedPropertyName] = args.constraints;
        const relatedValue = (args.object as any)[relatedPropertyName];
        return value === relatedValue;
    }

}
xjreopfe

xjreopfe2#

下面是一个扩展的例子,它内联了验证器,并为它提供了一个默认消息,这样你就不必每次使用@IsEqualTo装饰器时都输入一个消息。

import { 
    registerDecorator, 
    ValidationArguments, 
    ValidationOptions 
} from 'class-validator';

export function IsEqualTo(property: string, validationOptions?: ValidationOptions) {
    return (object: any, propertyName: string) => {
      registerDecorator({
        name: 'isEqualTo',
        target: object.constructor,
        propertyName,
        constraints: [property],
        options: validationOptions,
        validator: {
          validate(value: any, args: ValidationArguments) {
          const [relatedPropertyName] = args.constraints;
          const relatedValue = (args.object as any)[relatedPropertyName];
          return value === relatedValue;
        },

        defaultMessage(args: ValidationArguments) {
          const [relatedPropertyName] = args.constraints;
          return `${propertyName} must match ${relatedPropertyName} exactly`;
        },
      },
    });
  };
}
58wvjzkj

58wvjzkj3#

公认的答案对我来说是相当不错的,但我们可能会犯拼写错误,如:

@Match('passwordd')
//              👆

因此,我想对Generics进行更严格的定义

@Match(SignUpDto, (s) => s.password)

匹配.装饰.ts

import { ClassConstructor } from "class-transformer";

export const Match = <T>(
  type: ClassConstructor<T>,
  property: (o: T) => any,
  validationOptions?: ValidationOptions,
) => {
  return (object: any, propertyName: string) => {
    registerDecorator({
      target: object.constructor,
      propertyName,
      options: validationOptions,
      constraints: [property],
      validator: MatchConstraint,
    });
  };
};

@ValidatorConstraint({ name: "Match" })
export class MatchConstraint implements ValidatorConstraintInterface {
  validate(value: any, args: ValidationArguments) {
    const [fn] = args.constraints;
    return fn(args.object) === value;
  }

  defaultMessage(args: ValidationArguments) {
    const [constraintProperty]: (() => any)[] = args.constraints;
    return `${constraintProperty} and ${args.property} does not match`;
  }
}

所以我们可以像这样使用Match装饰器:

export class SignUpDto {
  // ...
  password: string;

  // finally, we have 😎
  @Match(SignUpDto, (s) => s.password)
  passwordConfirm: string;
}
wfauudbj

wfauudbj4#

我喜欢IsEqualTo装饰器的方法,但我也担心在使用Dto中没有的属性时会出现错别字,因此我以下面的代码结束:

import {
  registerDecorator,
  ValidationArguments,
  ValidationOptions,
} from 'class-validator';

export function IsEqualTo<T>(
  property: keyof T,
  validationOptions?: ValidationOptions,
) {
  return (object: any, propertyName: string) => {
    registerDecorator({
      name: 'isEqualTo',
      target: object.constructor,
      propertyName,
      constraints: [property],
      options: validationOptions,
      validator: {
        validate(value: any, args: ValidationArguments) {
          const [relatedPropertyName] = args.constraints;
          const relatedValue = (args.object as any)[relatedPropertyName];
          return value === relatedValue;
        },

        defaultMessage(args: ValidationArguments) {
          const [relatedPropertyName] = args.constraints;
          return `${propertyName} must match ${relatedPropertyName} exactly`;
        },
      },
    });
  };
}

像这样使用它:

export class CreateUserDto {
  @IsEqualTo<CreateUserDto>('password')
  readonly password_confirmation: string;
}
kq4fsx7k

kq4fsx7k5#

我喜欢这个公认的答案,但是我认为我们可以简化这个过程,方法是将我们想要验证的属性作为constraints数组中的字符串传递给。
示例:

@ValidatorConstraint({ name: 'CustomMatchPasswords', async: false })
export class CustomMatchPasswords implements ValidatorConstraintInterface {
   validate(password: string, args: ValidationArguments) {

      if (password !== (args.object as any)[args.constraints[0]]) return false;
      return true;
   }

   defaultMessage(args: ValidationArguments) {
      return "Passwords do not match!";
   }
}

然后我们可以使用验证器而不需要创建装饰器:

@IsString()
    @MinLength(4)
    @MaxLength(20)
    @Matches(/((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$/, {message: 'password too weak'})
    password: string;

    @IsString()
    @MinLength(4)
    @MaxLength(20)
    @Validate(CustomMatchPasswords, ['password'])
    passwordConfirm: string;
u0sqgete

u0sqgete6#

@MinLength(requiredlength ex: 5)
 @MaxLength(requiredlength ex:5)

正在最新版本中工作,以便验证长度,我们可以使用它。

相关问题