【问题标题】:How can I implement joi-password-complexity in Joi validation?如何在 Joi 验证中实现 joi-password-complexity?
【发布时间】:2020-05-26 12:07:21
【问题描述】:

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

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

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

(node:14872) UnhandledPromiseRejectionWarning: AssertionError [ERR_ASSERTION]:无效的架构内容: (密码.$_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”关键字会引发另一个错误(不是构造函数)。

感谢任何帮助!

【问题讨论】:

    标签: node.js mongodb mongoose passwords joi


    【解决方案1】:

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

    • @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);
    }
    

    【讨论】:

    • 感谢您的回复。我安装了正确的版本。我复制粘贴了您的代码,但在发送请求时不断收到错误消息:UnhandledPromiseRejectionWarning: AssertionError [ERR_ASSERTION]: Invalid schema content: at new AssertionError (internal/assert.js:269:11)
    • 啊,我还把你的schema 包裹在了Joi.object 中,忘记了。它有效,例如here。那么问题可能不是来自 Joi 的架构,而是来自 Mongoose 的架构?
    • 谢谢!问题是我使用的是const Joi = require("joi"); 而不是const Joi = require('@hapi/joi');。有什么区别?
    • 不确定是否真的有区别,但joi-password-complexity 的内部require 可能会解析为一个不同的 对象(require 缓存已解析的包),这可能会导致奇怪的行为......我看不出任何其他原因,这是高度假设的!
    【解决方案2】:

    这是我解决问题的方法: 如果您使用的是 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;
    

    【讨论】:

    • 请注意这是一个 '@hapi/joi' 依赖而不是以前的 'joi' 版本!
    • 我认为这是来自 Mosh 的 Nodejs 课程(Vidly API)的代码形式。不过感谢您的解决方案。这正是我要寻找的。​​span>
    • stackoverflow.com/users/6901801/mr-spshuvo 是的,这是 Mosh 代码
    【解决方案3】:

    由于passwordComplexity()返回的是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);
    }
    

    【讨论】:

      【解决方案4】:

      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,
      };
      

      【讨论】:

        【解决方案5】:

        我必须添加 .default 来导入返回 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(),
        });
        

        【讨论】:

        【解决方案6】:

        另一种方式是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");
        }
        

        【讨论】:

          猜你喜欢
          • 2020-04-27
          • 1970-01-01
          • 2018-09-24
          • 2018-02-03
          • 1970-01-01
          • 2020-02-13
          • 2019-04-02
          • 2021-02-05
          • 1970-01-01
          相关资源
          最近更新 更多