Passport.js用户登录和身份验证

6

最近几天,我一直在使用Passport.js开发我的第一个用户登录和身份验证系统。尴尬的是,虽然我已经完成了它,并且它按预期工作,但我似乎并不完全理解代码本身,即使我已经阅读了很多文章并检查了许多在线示例。我没有问题理解其背后的过程以及为什么必须这样做。如果您能澄清代码某些部分,我将不胜感激。这是存储在我的app.js文件中的可用代码:

// Passport session setup
passport.serializeUser(function (user, done) {
    done(null, user._id);
});

passport.deserializeUser(function (id, done) {
    User.findById(id, function(err, user) {
        done(err, user);
    });
});

// Use the Local Strategy within passport
passport.use(new LocalStrategy(function (username, password, done) {
    User.findOne({ username: username }, function(err, user) {
        if (err) {
            return done(err);
        }

        if (!user) {
            return done(null, false, { message: 'Unknown user: ' + username});
        }

        user.comparePassword(password, function(err, isMatch) {
            if (err) {
                return done(err);
            }

            if (isMatch) {
                return done(null, user);
            } else {
                return done(null, false, { message: 'Invalid Password' });
            }
        });
    });
}));

var app = module.exports = express();

app.configure(function () {
    app.set('views', path.join(__dirname + '/views'));
    app.set('view engine', 'html');
    app.engine('html', hbs.__express);
    app.use(express.logger());
    app.use(express.cookieParser());
    app.use(express.bodyParser());
    app.use(express.methodOverride());
    app.use(express.session({ secret: 'xxx' }));    
    app.use(passport.initialize());
    app.use(passport.session());
    app.use(app.router);
    app.use(express.static(path.join(__dirname + '/public')));

});

我正在使用 MongoDB(用户 - mongoose 模型)。此外,为了将密码存储在数据库中,我目前正在使用 bcrypt。
我认为我不理解的最关键部分是“done”回调函数。我能理解它只是传递一些值,并且我知道第一个参数是错误,第二个参数是数据。尽管如此,我仍然没有完全掌握它,因为我没有明确地将其作为参数之一提供。例如,如果我有这样一个函数:
// Random Function
var randomFunction = function (a, b, done) {
    done(a, b);
};

// Then I would call the randomFunction providing my own **done**
randomFunction('Random', 'Words', function(a, b) { return a + b; });

然而,在我的例子中,我并没有指定 done 回调函数。它是一个必须的回调函数参数还是与正常中间件中的下一个函数相同:

function middleware (req, res, next) {
    next(req.user); // pass the req.user to next middleware
}

此外,Passport.js将处理的用户绑定到哪里?它会将其绑定到req.user吗?如何将其传递给某些视图,以便例如显示用户名?
期待您的反馈!
谢谢!
1个回答

3

完成回调函数

查看本地策略(Local Strategy)的代码:

function Strategy(options, verify) {
  ...
  this._verify = verify;
  ...
}

verify是策略用于验证用户的函数,你在这里进行了指定:

passport.use(new LocalStrategy(function (username, password, done) {
    // your verification code here
}));

稍后在策略中,您可以找到authenticate方法,该方法调用上一步中的verify函数:

this._verify(username, password, verified);

所以,现在你知道了usernamepassworddone==verified来自哪里。稍后在你的代码中,你将使用(err, user, info)参数调用done回调函数。简单地说,done是必需的,以完成用户验证的异步过程。
关于req.user,你是正确的。因此,你可以通过两种方式将它传递给你的视图:
  1. As an argument of res.render function. See docs

    res.render('some-template', { name: req.user });
    
  2. Use res.locals as some kind of context provider (now user object will be available in all the views that are defined in app.router). See docs

    // before app.use(app.router);
    app.use(function(req, res, next) {
       res.locals.user = req.user;
       next();
    });
    

非常感谢您的反馈!据我所知,done是一个回调函数,用于从中间件返回信息。我指的是3个参数(err、user、info)。基本上,我可以将done回调视为特定中间件的返回(以高层次的方式)吗? - vladzam
1
如果我正确理解了你的问题,那么不是的。done仅用于向下一级提供一些数据。在调用done()后,您的验证代码将以正常方式执行,这就是为什么您应该使用return done(err);来停止执行验证代码的原因。这是异步操作的常见情况。 - Peter Gerasimenko
这就是我的意思^^我想我的回答有点含糊不清:)非常感谢您的反馈,我真的很感激! - vladzam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接