【问题标题】:Formik, Yup Password Strength Validation with ReactFormik,是的,使用 React 进行密码强度验证
【发布时间】:2019-08-22 09:27:38
【问题描述】:

我对 React 还很陌生,我有一个注册页面,其中有一个密码字段要使用正则表达式进行验证。

我正在使用 Formik 和 Yup 进行验证,但我遇到了一个错误,当我在“密码”字段中键入时,它显示调用长度函数的属性未定义。

是的,有一个名为“matches”的函数,我试图用它来检查正则表达式。那是我得到这个错误的时候。我删除了这个验证,之后设置为密码字段的其他验证工作正常。

下面是 SignUp.js 文件的代码:-

import React from "react";
import Button from "react-bootstrap/Button";
import Form from "react-bootstrap/Form";
import "./SignUp.css";
import * as yup from "yup";
import { Formik } from "formik";

const schema = yup.object({
  username: yup.string().required('Please Enter a username'),
  email: yup
    .string()
    .email()
    .required('Please Enter your Email'),
  confirmEmail: yup
    .string()
    .email()
    .required()
    .oneOf([yup.ref("email"), null], "Emails must match"),
  password: yup
    .string()
    .required('Please Enter your password')
    .matches(
      "^(?=.*[A-Za-z])(?=.*d)(?=.*[@$!%*#?&])[A-Za-zd@$!%*#?&]{8,}$",
      "Must Contain 8 Characters, One Uppercase, One Lowercase, One Number and one special case Character"
    ),
  confirmPassword: yup
    .string()
    .required()
    .oneOf([yup.ref("password"), null], "Passwords must match")
});

const SignUp = props => {
  return (
    <Formik
    validationSchema={schema}
    onSubmit={console.log}
    initialValues={{
      username: "",
      email : "",
      confirmEmail : "",
      password: "",
      confirmPassword : ""
    }}
  >
  {({
    handleSubmit,
    handleChange,
    handleBlur,
    values,
    touched,
    isValid,
    errors,
  }) => (
    <div className="SignUpForm">
      <h1 className="SignInHeading">SIGN UP</h1>
      <Form noValidate onSubmit={handleSubmit}>
        <Form.Group controlId="formBasicUserName">
          <Form.Control
            size="lg"
            className="SignUpFormControls"
            type="text"
            name="username"
            value={values.username}
            onChange={handleChange}
            placeholder="Username"
            isInvalid={!!errors.username}
          />
          <Form.Control.Feedback className="FeedBack" type="invalid">
          {errors.username}
        </Form.Control.Feedback>
        </Form.Group>

        <Form.Group controlId="formBasicEmail">
          <Form.Control
            type="email"
            placeholder="Email"
            value={values.email}
            onChange={handleChange}
            name="email"
            className="SignUpFormControls"
            size="lg"
            isInvalid={!!errors.email}
          />
          <Form.Control.Feedback className="FeedBack" type="invalid">
          {errors.email}
        </Form.Control.Feedback>
        </Form.Group>

        <Form.Group controlId="formBasicConfirmEmail">
          <Form.Control
            type="email"
            className="SignUpFormControls"
            size="lg"
            name="confirmEmail"
            value = {values.confirmEmail}
            onChange={handleChange}
            placeholder="Confirm Email"
            isInvalid={!!errors.confirmEmail}
          />
          <Form.Control.Feedback className="FeedBack" type="invalid">
          {errors.confirmEmail}
        </Form.Control.Feedback>
        </Form.Group>

        <Form.Group controlId="formBasicPassword">
          <Form.Control
            className="SignUpFormControls"
            size="lg"
            type="password"
            name="password"
            value={values.password}
            onChange={handleChange}
            placeholder="Password"
            isInvalid={!!errors.password}
          />
          <Form.Control.Feedback className="FeedBack" type="invalid">
          {errors.password}
        </Form.Control.Feedback>
        </Form.Group>

        <Form.Group controlId="formBasicConfirmPassword">
          <Form.Control
            className="SignUpFormControls"
            size="lg"
            name="confirmPassword"
            onChange={handleChange}
            type="password"
            value={values.confirmPassword}
            placeholder="Confirm Password"
            isInvalid={!!errors.confirmPassword}
          /><Form.Control.Feedback className="FeedBack" type="invalid">
          {errors.confirmPassword}
        </Form.Control.Feedback>
        </Form.Group>

        <Button variant="primary" className="SignUpButton" type="submit">
          Sign Up
        </Button>
        <Form.Text>
          Already a User?{" "}
          <a href="#signin" onClick={props.toggle}>
            Sign In
          </a>
        </Form.Text>
      </Form>
    </div>)}
    </Formik>
  );
};

export default SignUp;

这是 chrome 控制台中的错误:-

formik.esm.js:721 Uncaught (in promise) TypeError: Cannot read property 'length' of undefined
    at yupToFormErrors (formik.esm.js:721)
    at formik.esm.js:276

【问题讨论】:

  • 错误没有说长度未定义,它表示属性长度在未定义时不存在。
  • 不要添加错误消息的图像,而是将文本复制粘贴到问题中。
  • 我已经做出了改变。你知道为什么会出现这种情况吗?
  • 这将是一个很好的做法,并且更容易管理更简单地更细化地验证每个密码标准。例如匹配长度太短,然后没有数字,等等。

标签: javascript reactjs typescript formik yup


【解决方案1】:
yup.addMethod(yup.string, "strongPassword", strongPasswordMethod);

function strongPasswordMethod() {
    return this.test("strongPasswordTest", _, function (value) {
        const { path, createError } = this;
        switch (Boolean(value)) {
            case !/^(?=.*[a-z])/.test(value):
                return createError({ path, message: "password must include lowercase letter" });
            case !/^(?=.*[A-Z])/.test(value):
                return createError({ path, message: "password must include uppercase letter" });
            case !/^(?=.*[0-9])/.test(value):
                return createError({ path, message: "password must include digit" });
            case !/^(?=.*[!@#\$%\^&\*])/.test(value):
                return createError({ path, message: "password must include special character" });
            default:
                return true;
        }
    });
};

const schema = yup.object().shape({
    password: yup.string().required().strongPassword()
});

【讨论】:

  • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
【解决方案2】:

您需要将一个实际的 RegExp 对象传递给matches,而不是一个字符串。只需将密码架构中的双引号替换为正斜杠即可:

编辑:更新为使用来自@Bren 的正则表达式

password: yup
    .string()
    .required('Please Enter your password')
    .matches(
      /^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#\$%\^&\*])(?=.{8,})/,
      "Must Contain 8 Characters, One Uppercase, One Lowercase, One Number and One Special Case Character"
    ),

【讨论】:

  • 这不能回答问题,但对于任何尝试使用正则表达式并意识到它不能按预期工作的人,(?=.*d) 应该是 (?=.*\d),因为数字的表示是 @ 987654325@
  • 我可以不用大写提交,比如:admin12@
  • 用这个正则表达式,无法判断它是否同时包含大小写字母。
【解决方案3】:

考虑到以上所有答案并经过一些研究,可以采用一种综合方法来检查密码的强度:

password: Yup
    .string()
    .required('Required')
    .matches(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*#?&])[A-Za-z\d@$!%*#?&]{8,}$/,
    "Must Contain 8 Characters, One Uppercase, One Lowercase, One Number and one special case Character"
  )

但是,这种方法不适用于所有特殊字符。如果您想包括here 中列出的所有可能的特殊字符。该解决方案可以修改为:

password: Yup
    .string()
    .required('Required')
    .matches(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~])[A-Za-z\d!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~]{8,}$/,
    "Must Contain 8 Characters, One Uppercase, One Lowercase, One Number and one special case Character"
  )

这是我在应用程序中采用的解决方案。但这完全是您的选择,您希望在密码强度检查中包含/排除哪些特殊字符。

【讨论】:

    【解决方案4】:

    当我搜索这个答案时,我在网上找到的大多数答案(甚至在这个线程中标记为正确答案的答案)都是这样的,它不检查大写字符:

    password: yup
        .string()
        .required('Please Enter your password')
        .matches(
          /^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*#?&])[A-Za-z\d@$!%*#?&]{8,}$/,
          "Must Contain 8 Characters, One Uppercase, One Lowercase, One Number and one special case Character"
        ),
    

    但对我来说,这实际上并没有检查是否同时存在大写和小写字符。不过这确实对我有用(检查特殊字符、大写字符、小写字符和数字):

    password: yup
        .string()
        .required('Please Enter your password')
        .matches(
         /^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*])(?=.{8,})/,
          "Must Contain 8 Characters, One Uppercase, One Lowercase, One Number and one special case Character"
        ),
    

    【讨论】:

      【解决方案5】:

      昨晚遇到了这个问题,试图解决类似的 React+Formik+Yup 密码验证问题。总的来说,这里的解决方案很好。我只评论提供一个稍微不同的正则表达式:

      /^(?=.*[A-Z])(?=.*[a-z])(?=.*\d)(?=.*[^A-Za-z0-9]).{8,}$/
      

      这在第四次预测中有所不同。在这个版本中,它会寻找不是字母或数字的任何东西。以前的 RE 都将“特殊字符”的定义限制为 8 个左右的特定字符。这将匹配更广泛的范围。

      我最初使用了(?=.*[^\w]),它否定了“word”类(\w),但该类包括下划线。所以这样做不会把下划线算作特殊字符。

      【讨论】:

        【解决方案6】:

        这对我有用:

         password: yup
            .string()
            .required('Password is required')
            .matches(regExp)
            .min(6, 'Your password must be longer than 6 characters.')
        

        【讨论】:

        • 你没有包含regExp的值
        【解决方案7】:

        这就是我终于要开始工作了。

         password: Yup.string()
                  .required('Please Enter your password')
                  .matches(
        
                    /^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#\$%\^&\*])(?=.{8,})/,
                    "Must Contain 8 Characters, One Uppercase, One Lowercase, One Number and One Special Case Character"
                  ),
        

        我从这篇文章中获取了这个正则表达式字符串:https://www.thepolyglotdeveloper.com/2015/05/use-regex-to-test-password-strength-in-javascript/

        【讨论】:

        • 这个正则表达式非常正确。谢谢。
        【解决方案8】:

        以上都不适合我,我的解决方案就在下面

          password: yup
          .string()
          .required("Şifreniz kayıt olmak için gereklidir.")
          .matches(
            /^.*(?=.{8,})((?=.*[!@#$%^&*()\-_=+{};:,<.>]){1})(?=.*\d)((?=.*[a-z]){1})((?=.*[A-Z]){1}).*$/,
            "En Az 8 Karakter, Bir Büyük Harf, Bir Küçük Harf, Bir Rakam ve Bir Özel Karakter İçermelidir"
          )
        

        【讨论】:

          【解决方案9】:

          好的,经过几个小时的修补,我决定改用自己的自定义验证。

          这是我所做的:-

          password: yup
              .string()
              .required("Please Enter your password")
              .test(
                "regex",
                "Password must be min 8 characters, and have 1 Special Character, 1 Uppercase, 1 Number and 1 Lowercase",
                val => {
                  let regExp = new RegExp(
                    "^(?=.*\\d)(?=.*[!@#$%^&*])(?=.*[a-z])(?=.*[A-Z]).{8,}$"
                  );
                  console.log(regExp.test(val), regExp, val);
                  return regExp.test(val);
                }
              )
          

          目前,这工作正常。但我真的很想知道为什么会弹出错误。如果您能够找到解决方案,请将其作为答案发布,如果它对我有用,我会将其标记为正确答案。谢谢。

          【讨论】:

          • 这不能回答问题,但对于任何尝试使用正则表达式并意识到它不能按预期工作的人,(?=.*\\d) 应该是 (?=.*\d),因为数字的表示是 @ 987654324@
          • 以上正则表达式接受空格。
          猜你喜欢
          • 2021-02-09
          • 2019-09-12
          • 2019-12-26
          • 2020-04-21
          • 2014-05-23
          • 2019-10-09
          • 1970-01-01
          • 1970-01-01
          • 2018-06-29
          相关资源
          最近更新 更多