0

我正在使用 node.js 我已经可以从注册 html 页面发布。但是下面的代码

exports.login = function (req, res, next) {


if (req.body && req.body.email && req.body.password)  {

    var userLogin = new User ({

        email: req.body.email,
        password: req.body.password
    });

    userLogin.findOne(function(err) {
        if (!err) {
            res.redirect('/about.html');
        } else {
            res.redirect('http://google.com');
            next(err);
        }
    });
} else {
    next(new Error('Incorrect POST'));
}

};

我遇到的问题是 userLogin.findOne 没有工作,因为它说 findOne 未定义。

链接到的 model.js 文件是:

var mongoose = require('mongoose'),
Schema = mongoose.Schema,
bcrypt = require('bcrypt-nodejs'),
SALT_WORK_FACTOR = 10;
 // these values can be whatever you want - we're defaulting to a
// max of 5 attempts, resulting in a 2 hour lock
MAX_LOGIN_ATTEMPTS = 5,
LOCK_TIME = 2 * 60 * 60 * 1000;



var UserSchema = new Schema({ 
email: { type: String, required: true, lowercase:true, index: { unique: true } },
password: { type: String, required: true },
firstName: {type: String, required: true},
lastName: {type: String, required: true},
phone: {type: Number, required: true},
birthday: {type: Date, required: true},


loginAttempts: { type: Number, required: true, default: 0 },
lockUntil: { type: Number }

});

UserSchema.virtual('isLocked').get(function() {
// check for a future lockUntil timestamp
return !!(this.lockUntil && this.lockUntil > Date.now());
});


//password hashing middleware

UserSchema.pre('save', function(next) {
var user = this;

// only hash the password if it has been modified (or is new)
if (!user.isModified('password')) return next();
// generate a salt
bcrypt.genSalt(SALT_WORK_FACTOR, function(err, salt) {
    if (err) return next(err);
    // hash the password along with our new salt
    bcrypt.hash(user.password, salt, null, function(err, hash) {
        if (err) return next(err);
        // override the cleartext password with the hashed one
        user.password = hash;
        next();
    });
});    
});
//password verification

UserSchema.methods.comparePassword = function(candidatePassword, cb) {
bcrypt.compare(candidatePassword, this.password, function(err, isMatch) {
    if (err) return cb(err);
    cb(null, isMatch);
});
};


UserSchema.methods.incLoginAttempts = function(cb) {
// if we have a previous lock that has expired, restart at 1
if (this.lockUntil && this.lockUntil < Date.now()) {
    return this.update({
        $set: { loginAttempts: 1 },
        $unset: { lockUntil: 1 }
    }, cb);
}
// otherwise we're incrementing
var updates = { $inc: { loginAttempts: 1 } };
// lock the account if we've reached max attempts and it's not locked already
if (this.loginAttempts + 1 >= MAX_LOGIN_ATTEMPTS && !this.isLocked) {
    updates.$set = { lockUntil: Date.now() + LOCK_TIME };
}
return this.update(updates, cb);
};

// expose enum on the model, and provide an internal convenience reference 
var reasons = UserSchema.statics.failedLogin = {
NOT_FOUND: 0,
PASSWORD_INCORRECT: 1,
MAX_ATTEMPTS: 2
};

UserSchema.statics.getAuthenticated = function(email, password, cb) {
this.findOne({ email: email }, function(err, user) {
    if (err) return cb(err);

    // make sure the user exists
    if (!user) {
        return cb(null, null, reasons.NOT_FOUND);
    }

    // check if the account is currently locked
    if (user.isLocked) {
        // just increment login attempts if account is already locked
        return user.incLoginAttempts(function(err) {
            if (err) return cb(err);
            return cb(null, null, reasons.MAX_ATTEMPTS);
        });
    }

    // test for a matching password
    user.comparePassword(password, function(err, isMatch) {
        if (err) return cb(err);

        // check if the password was a match
        if (isMatch) {
            // if there's no lock or failed attempts, just return the user
            if (!user.loginAttempts && !user.lockUntil) return cb(null, user);
            // reset attempts and lock info
            var updates = {
                $set: { loginAttempts: 0 },
                $unset: { lockUntil: 1 }
            };
            return user.update(updates, function(err) {
                if (err) return cb(err);
                return cb(null, user);
            });
        }

        // password is incorrect, so increment login attempts before responding
        user.incLoginAttempts(function(err) {
            if (err) return cb(err);
            return cb(null, null, reasons.PASSWORD_INCORRECT);
        });
    });
});
};




module.exports = mongoose.model('User', UserSchema);
4

1 回答 1

0

在您的代码中,userLogin是 User 模型的一个实例,这意味着您已经创建了一个document。正如猫鼬查询的文档所述,查询是使用“静态辅助方法”处理的,这意味着它们在模型实例(即文档)上不可用。

我认为您可能希望您的代码看起来更像这样,其中userLogin是一个保存查询条件的对象,然后您可以使用User模型的.findOne方法来执行查询。

var userLogin = {
    email: req.body.email,
    password: req.body.password
};

User.findOne(userLogin, function(err) {
    if (!err) {
        res.redirect('/about.html');
    } else {
        res.redirect('http://google.com');
        next(err);
    }
});

编辑:好的,所以上面回答了为什么 findOne 未定义的问题。

第二个问题是“为什么不对用户进行身份验证?”

代码重定向到(我假设)“/about.html”页面的原因是因为这正是代码所做的......正如所写的那样。

UserSchema.statics.getAuthenticated要进行身份验证(从技术上讲,我们正在对最初未提出的问题提出新的答案):您需要调用modules.js. 那将需要这样的代码(从大部分代码起源的教程稍作修改):

User.getAuthenticated('<valid_email>', '<valid_password>', function(err, user, reason) {
        if (err) throw err;

        if (user) {
            // handle login success
            // note, handling success is more than a res.redirect call
            // if you need to deal with session, state, cookies, etc...
            return;
        }

        // otherwise we can determine why we failed
        var reasons = User.failedLogin;
        switch (reason) {
            case reasons.NOT_FOUND:
            case reasons.PASSWORD_INCORRECT:
                // note: these cases are usually treated the same - don't tell
                // the user *why* the login failed, only that it did
                break;
            case reasons.MAX_ATTEMPTS:
                // send email or otherwise notify user that account is
                // temporarily locked
                break;
        }
    });

作为一个侧节点,我建议您将everyauth 或passport.js 作为可以为您完成大部分工作的模块。那时,您主要关心的是为用户 CRUD 编写代码,同时模块为您处理会话、cookie、序列化/反序列化等。如果您有任何计划通过 google、facebook 等包括 OAUTH 登录,这是双重事实。

于 2013-05-26T13:07:59.657 回答