如何在 Joi 验证中实现 joi-password-complexity?

How can I implement joi-password-complexity in Joi validation?

我想在用户注册时使用 joi-password-complexity 包来强制密码复杂性。

https://github.com/kamronbatman/joi-password-complexity

我试过了,但出现以下错误:

(node:14872) UnhandledPromiseRejectionWarning: AssertionError [ERR_ASSERTION]: Invalid schema content: (password.$_root.alternatives)

这是我正在使用的代码:

const mongoose = require("mongoose");
const Joi = require("joi");
const passwordComplexity = require("joi-password-complexity");

const complexityOptions = {
  min: 5,
  max: 250,
  lowerCase: 1,
  upperCase: 1,
  numeric: 1,
  symbol: 1,
  requirementCount: 2,
};

const userSchema = new mongoose.Schema({
  name: {
    type: String,
    minlenght: 1,
    maxlength: 55,
    required: true
  },
  email: {
    type: String,
    minlength: 5,
    maxlength: 255,
    unique: true,
    required: true
  },
  password: {
    type: String,
    minlength: 5,
    maxlength: 1024,
    required: true
  }
})

const User = mongoose.model("User", userSchema);

function validateUser(user) {
  const schema = {
    name: Joi.string().min(1).max(55).required(),
    email: Joi.string().min(5).max(255).required().email(),
    password: passwordComplexity(complexityOptions) // This is not working
  }
  return Joi.validate(user, schema);
}

exports.User = User;
exports.validate = validateUser;

我也试着按照这个例子:https://forum.codewithmosh.com/d/215-joi-password-complexity-problem 但它似乎过时了,因为 "new" 关键字会抛出另一个错误(不是构造函数)。

感谢任何帮助!

无法重现您的确切错误,但我是这样工作的:

  • @hapi/joi: ^17.1.0(撰写本文时最新版本,也适用于 16.1.8)
  • joi-password-complexity: ^4.0.0(也是最新的)

代码:

function validateUser(user) {
  // no change here
  const schema = Joi.object({
    name: Joi.string().min(1).max(55).required(),
    email: Joi.string().min(5).max(255).required().email(),
    password: passwordComplexity(complexityOptions) // This is not working
  });
  // note that we call schema.validate instead of Joi.validate
  // (which doesn't seem to exist anymore)
  return schema.validate(user);
}

以下是我解决问题的方法: 如果您使用的是 joi@14.3.1 或更早版本,请安装 joi-password-complexity@2.0.1 然后尝试此代码:

User.js model

const mongoose = require("mongoose");
const Joi = require("joi");
const PasswordComplexity = require("joi-password-complexity");

const userSchema = new mongoose.Schema({
  name: {
    type: String,
    required: true,
    trim: true
  },
  email: { type: String, required: true, unique: true },
  password: { type: String, required: true }
});

const User = mongoose.model("User", userSchema);

function validateUser(user) {
  const schema = {
    name: Joi.string()
      .min(3)
      .max(50)
      .required(),
    email: Joi.string()
      .email()
      .max(255)
      .required(),
    password:  new PasswordComplexity({
    min: 8,
    max: 25,
    lowerCase: 1,
    upperCase: 1,
    numeric: 1,
    symbol: 1,
    requirementCount: 4
  });
  };
  return Joi.validate(user, schema);
}

module.exports.validate = validateUser;
module.exports.User = User;

这将验证密码的复杂性,但要使密码成为必需的,您必须在您的路线中验证它...

Users.js route

const _ = require("lodash");
const express = require("express");
const { User, validate } = require("../models/user");

const router = express.Router();

//POST
router.post("/", async (req, res) => {
  const { error } = validate(req.body);
  if (error) return res.status(400).send(error.details[0].message);
  //
  if (!req.body.password) return res.status(400).send("Password is required..");

  let user = await User.findOne({ email: req.body.email });
  if (user) return res.status(400).send("User already registered..");

  user = new User(_.pick(req.body, ["name", "email", "password"]));
  await user.save();
  res.send(_.pick(user, ["_id", "name", "email"]));
});

module.exports = router;

由于 passwordComplexity() returns 是一个 Joi 对象,您可以流畅地编写 required。因此,您不必在路由器中编写额外的验证。

function validateUser(user) {
  // no change here
  const schema = Joi.object({
    name: Joi.string().min(1).max(55).required(),
    email: Joi.string().min(5).max(255).required().email(),
    password: passwordComplexity(complexityOptions).required()
  });
  // note that we call schema.validate instead of Joi.validate
  // (which doesn't seem to exist anymore)
  return schema.validate(user);
}

Joi 和 JPC 使用的版本: ├── ... ├── joi@17.2.1 ├── joi-password-complexity@4.2.1

必须更新验证功能以适应 JOI 的新更新版本。 Joi v16+

不再支持 joi.validate()
   const Joi = require("joi");
   const passwordComplexity = require("joi-password-complexity");

   function validateUser(user) {
      const schema = Joi.object({
        name: Joi.string().min(5).max(50).required(),
        email: Joi.string().min(5).max(255).required().email(),
        password: passwordComplexity(complexityOptions),
      });
      return schema.validate(user); // NOT >> Joi.validate(user, schema);  !!!!!
    }

complexityOptions 可以是这样的:

const complexityOptions = {
  min: 5,
  max: 1024,
  lowerCase: 1,
  upperCase: 1,
  numeric: 1,
  symbol: 1,
  requirementCount: 4,
};

我必须添加 .default 来导入 returns Joi 对象的函数。使用 Joi 17.3.0 和 joi-password-complexity 5.0.1,这对我有用:

const passwordComplexity = require('joi-password-complexity').default;

const schema = Joi.object({
  email: Joi.string().min(5).max(255).required().email(),
  password: passwordComplexity().required(),
});

另一种方式是Regex

const joi = require("joi");

const strongPasswordRegex = /^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$/;
const stringPassswordError = new Error("Password must be strong. At least one upper case alphabet. At least one lower case alphabet. At least one digit. At least one special character. Minimum eight in length")

const schema = joi.object().keys({
    username: joi.string().required().min(4).max(15),
    password: joi.string().regex(strongPasswordRegex).error(stringPassswordError).required()
});

const notValid = schema.validate({ username: "MHamzaRajput", password: "Admin@admin123" }).error;

if (notValid) {
    console.log(notValid.message);
} else {
    console.log("payload validated successfully");
}