我的方法错了吗?我对NodeJS,MongoDB,Joi,Bcrypt感到困惑

时间:2018-07-14 07:38:57

标签: node.js express mongoose bcrypt joi

我在使用NodeJS(ExpressJS),MongoDB,Joi验证模块和Bcrypt时遇到了一些问题。

我有用户API路由器和用户模型。 我的用户模型是这样:

const userSchema = new mongoose.Schema({
    name: {
        type: String,
        trim: true,
        minlength: [3, 'Adınızın Karakter Sayısı Uygun Değildir. Minimum 3, Maksimum 50 Adet Karakterden Oluşabilir.'],
        maxlength: [50, 'Adınızın Karakter Sayısı Uygun Değildir. Minimum 3, Maksimum 50 Adet Karakterden Oluşabilir.'],
        validate: {
            validator: function(v) {
                return /^[A-Za-zıİüÜğĞşŞçÇöÖ ]+$/.test(v);
            },
            message: 'Uygun Formatta İsim Giriniz. (Geçerli Karakterler: a-z, A-Z, boşluk karakteri.)'
        },
        match: [/^[A-Za-zıİüÜğĞşŞçÇöÖ ]+$/, 'Uygun Formatta İsim Giriniz. (Geçerli Karakterler: a-z, A-Z, boşluk karakteri.)']
    },
    lastname: {
        type: String,
        trim: true,
        minlength: [3, 'Soyadınızın Karakter Sayısı Uygun Değildir. Minimum 3, Maksimum 50 Adet Karakterden Oluşabilir.'],
        maxlength: [50, 'Adınızın Karakter Sayısı Uygun Değildir. Minimum 3, Maksimum 50 Adet Karakterden Oluşabilir.'],
        validate: {
            validator: function(v) {
                return /^[A-Za-zıİüÜğĞşŞçÇöÖ ]+$/.test(v);
            },
            message: 'Uygun Formatta Soyisim Giriniz. (Geçerli Karakterler: a-z, A-Z, boşluk karakteri.)'
        },
        match: [/^[A-Za-zıİüÜğĞşŞçÇöÖ ]+$/, 'Uygun Formatta Soyisim Giriniz. (Geçerli Karakterler: a-z, A-Z, boşluk karakteri.)']
    },
    username: {
        type: String,
        trim: true,
        index: true,
        unique: true,
        minlength: [3, 'Kullanıcı Adınızın Karakter Sayısı Uygun Değildir. Minimum 3, Maksimum 30 Adet Karakterden Oluşabilir.'],
        maxlength: [20, 'Kullanıcı Adınızın Karakter Sayısı Uygun Değildir. Minimum 3, Maksimum 30 Adet Karakterden Oluşabilir.'],
        validate: {
            validator: function(v) {
                let re = /^\w+$/;
                return re.test(v);
            },
            message: 'Uygun Formatta Kullanıcı Adı Giriniz. (Geçerli Karakterler: a-z, A-Z, _.)'
        },
        match: [/^\w+$/, 'Uygun Formatta Kullanıcı Adı Giriniz. (Geçerli Karakterler: a-z, A-Z, _.)']
    },
    email: {
        type: String,
        trim: true,
        index: true,
        unique: true,
        validate: {
            validator: function(v) {
                let re = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/;
                return re.test(v);
            },
        message: 'Uygun Formatta E-Posta Adresi Giriniz.'
        },
        match: [/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/, 'Uygun Formatta E-Posta Adresi Giriniz.']
    },
    password: {
        type: String,
        trim: true,
        required: [true, 'Şifrenizi Girmeniz Gerekmektedir.'],
        minlength: 5,
        maxlength: 1024
    },
    elo: {
        type: Number,
        min: 0,
        required: false,
        default: 0
    },
    rank: {
        type: Number,
        min: -1,
        required: false,
        default: 0
    },
    registerDate: {
        type: Date,
        default: Date.now
    },
    isAdmin: {
        type: Boolean,
        required: true,
        default: false
    }
});

这是Joi验证模式:

const Schema = {
    name: Joi.string().min(3).max(50).regex(/^[A-Za-zıİüÜğĞşŞçÇöÖ ]+$/),
    lastname: Joi.string().min(3).max(50).regex(/^[A-Za-zıİüÜğĞşŞçÇöÖ ]+$/),
    username: Joi.string().required().min(3).max(25).regex(/^\w+$/),
    email: Joi.string().required().min(3).email(),
    password: Joi.string().required().min(5).max(255),
    elo: Joi.number().default(0).min(0),
    rank: Joi.number().default(0).min(-1),
    isAdmin: Joi.boolean().default(false)
};

这是示例用户:

_id:5b47aae43cf7710e7047c033
elo:0
rank:0
isAdmin:true
name:"Furkan"
lastname:"Taştan"
username:"praaven"
email:"furkantastan@superonline.com"
password:"$2b$10$4xKTxmQnV5mnGrCccpQsY.A8j5ACCdmCHIihDdW0NXmcOcRCcwwPq"
registerDate:2018-07-12 22:24:20.778
__v:0

我对Update API Router感到困惑。

router.put('/:id', auth, async (req, res) => {
    try {
        const errorId = validateUserId(req.params.id);
        if(errorId.error) return res.status(400).send({'Hata': errorId.error.details[0].message});
        const { error } = validateUser(req.body);
        if(error) return res.status(400).send({'Hata': error.details[0].message});
        const salt = await bcyript.genSalt(10);
        const user = await User.findByIdAndUpdate(req.params.id, {
            name: req.body.name,
            lastname: req.body.lastname,
            username: req.body.username,
            email: req.body.email,
            password: await bcyript.hash(req.body.password, salt),
            elo: req.body.elo,
            rank: req.body.rank,
            isAdmin: req.body.isAdmin
        }, { new: true, runValidators: true, context: 'query' });
        if(!user) return res.status(404).send({'Hata': 'Belirtilen ID\'ye Sahip Kullanıcı Bulunamadı.'});
        res.status(200).send(_.pick(user, ['_id', 'name', 'lastname', 'username', 'email', 'elo', 'rank', 'registerDate', 'isAdmin']));
    } catch(e) {
        res.status(400).send({ 'Hata': e.message.replace(/(Validation failed|email|username|phone|team)/gi, v => arrayMap[v]) });
    }
});

问题是,为什么我需要每个更新用户的密码?我不需要用户密码,我想在可选密码上使用它。我认为,我的Update Router是错的,我是NodeJS RESTful API编码的新手,您能帮助我实现它的真实性吗?

谢谢,祝你有美好的一天!

2 个答案:

答案 0 :(得分:2)

您已经在Schema级别的此处验证密码字段:

password: {
        type: String,
        trim: true,
        required: [true, 'Şifrenizi Girmeniz Gerekmektedir.'],
        minlength: 5,
        maxlength: 1024
    },

因此无需在required()模式内使用JOI对其进行重新验证。

由于您正在使用Mongoose,因此可以在pre内部使用userSchema函数。像这样:

/**
 * Hash password with blowfish algorithm (bcrypt) before saving it in to the database
 */
userSchema.pre('save', function(next) {
    var user = this;

    // only hash the password if it has been modified
    if (!user.isModified('password'))
        return next();

    // password will be hashed only if it has changed
    user.password = bcrypt.hash(user.password, bcrypt.genSalt(10));
    next();
});

答案 1 :(得分:2)

这确实是由于您在JOI模式中放置了required()

作为解决方案,您可以通过多种方式来实现。您可能希望公开另一个API,以专门处理密码和用户名的细微差别。以这种方式,您最终创建了两个单独的JOI模式来处理两种不同的情况-在真正需要时以及在更新详细信息时更改密码(我不确定在更新详细信息时来回移动密码是否很好想法)。

附录:尽管如此,我注意到您实际上在将数据从请求主体传递到数据库模型时并未对数据进行任何转换(密码除外)-我​​不确定您为什么希望对于该实例,请两次验证此数据(请记住,您在更新的同时也打开了runValidators开关)。