Express4 和护照:无法验证

Posted

技术标签:

【中文标题】Express4 和护照:无法验证【英文标题】:Express4 and passport: Unable to authenticate 【发布时间】:2015-04-18 19:07:00 【问题描述】:

我正在学习 javascript 和 node.js。如您所知,任何节点应用程序最重要的部分之一是登录模块,因此我开始使用护照和本地护照,但我无法理解护照的身份验证方式。我对护照认证过程的理解如下:

'use strict';

var express = require('express');
var app = express();
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var dbConfig = require('./settings/db.js');
var mongoose = require('mongoose');
var expressSession = require('express-session');
var flash = require('connect-flash');

mongoose.connect(dbConfig.url);

app.use(expressSession(
  secret: 'mySecretKey'
));
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());

var server = app.listen(3000, function() 
  var host = server.address().address;
  var port = server.address().port;

  console.log('Admin app started at: %s %s ', host, port);
);

passport.serializeUser(function(user, done) 
  console.log('serializing user!');
  done(null, 'Hi');
);

passport.deserializeUser(function(id, done) 
  console.log('deserializing user');
  done(null, 
    '_id': 'Hi',
    'username': 'shankhs',
    'password': 'admin'
  );
);

var isAuthenticated = function(req, res, next) 
  if (req.isAuthenticated()) 
    console.log('Authenticated');
    console.log(req);
    next();
  
  console.log('redirecting to /');
  console.log(req.isAuthenticated());
  res.redirect('/');
;

app.get('/', function(req, res, next) 
  var fileOptions = 
    root: __dirname,
    dotfiles: 'deny',
    headers: 
      'x-timestamp': Date.now(),
      'x-sent': true
    
  ;
  res.sendFile('login.html', fileOptions, function(err) 
    if (err) 
      console.log(err);
      res.status(err.status).end();
     else 
      console.log('send login.html!' + Date.now());
    
  );
);

app.get('/admin', isAuthenticated, function(req, res, next) 
  var fileOptions = 
    root: __dirname,
    headers: 
      'x-timestamp': Date.now(),
      'x-sent': true
    
  ;
  var fileName = 'index.html';
  res.sendFile(fileName, fileOptions, function(err) 
    if (err) 
      console.log(err);
      res.status(err.status).end();
     else 
      console.log('Send index.html' + Date.now());
    
  );
);

passport.use('login', new LocalStrategy(
  function(req, username, password, done) 
    console.log('using passport!');
    console.log(req.body.username);
    console.log(req.body.password);
    done(null, 
      '_id': 'Hi',
      'username': 'shankhs',
      'password': 'admin'
    );
  
));

app.post('/login', function(req, res) 
  console.log(req.params);
  passport.authenticate('login', 
    successRedirect: '/admin',
    failureRedirect: '/',
    failureFlash: true
  )
);
    对 /login 路由的发布请求会调用异步 passport.authenticate 调用。 此 passport.authenticate 将“策略”作为参数 此策略被调用,它返回另一个“完成”异步调用(在我的情况下)没有错误和用户对象 在“完成”调用之后,调用 serializeUser 并将页面重定向到 /admin 如果有任何后续请求或调用任何具有 isAuthenticated 挂钩的 url,则 passport.initialize 会检查 req.passport.user 对象是否为空。 如果为空,则再次重复验证过程。 如果不是,passport.session 会调用 passport.deserializeUser 来创建 req.user 对象

我的问题如下:

    在“登录”策略中,这三个永远不会被记录:

    console.log('使用护照!'); console.log(req.body.username); console.log(req.body.password);

这是否意味着我的“登录”策略永远不会被调用?

    同样,从不调用 serializeUser 和 deserializeUser 中的 console.logs。所以这些函数也没有被调用?

如果我对护照库的理解是正确的,我是否缺少任何要调用的函数?

谢谢

【问题讨论】:

【参考方案1】:

对于未来的勇士:

这就是护照的工作方式。护照如何工作的详细解释是here

这里缺少的是对 /login 的 post 调用中的 bodyparser。你可能认为护照知道如何解析 req.body!错误的!它没有! Express v 4 及更高版本的正文解析器必须独立安装并用作:

var bodyParser = require('body-parser');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded(
  extended: true
));

在post请求中:

app.post('/login', function(req, res, next) 
  console.log('in login post!');
  console.log('body parsing: ' + req.body.username + ' ' + req.body.password);
  passport.authenticate('login', function(err, user, info) 
    if (err) 
      console.log('passport err: ' + err);
      return next(err);
    
    if (!user) 
      console.log('no user found!');
      return res.redirect('/');
    
    req.logIn(user, function(err) 
      if (err) 
        console.log('login error: ' + err);
        return next(err);
      
      return res.redirect('/admin');
    );
  )(req, res, next);
);

如您所见,我编写了一个自定义的 logIn 回调函数,它比successRedirect 和failureRedirect 更有意义且易于调试。如果没有 body-parser,自定义函数将无法工作,因为 passport 不知道如何解析 req.body。

护照的api doc应该提到这一点!好吧,既然一切都按预期进行,世界现在变得有意义了!

【讨论】:

(req, res, next) 在最后但第二行是强制性的吗?因为,我正在为我的应用程序编写本地策略,如果没有它,它似乎无法工作;但是,当我通过它时,它起作用了!我之前曾与本地护照合作过,并且不必在那里通过,但在这方面却没有! 是的,这是必需的。如果我没记错的话,它是调用匿名方法的 javascript 方式。

以上是关于Express4 和护照:无法验证的主要内容,如果未能解决你的问题,请参考以下文章

Node/Express 的 Passport 身份验证中间件 - 如何保护所有路由

NodeJs Express - 将请求参数传递给护照身份验证

Apollo express 没有快速护照会话

我应该如何在登录时使用续集和护照获得验证错误

使用护照进行身份验证后,如何在 React FROM express 中重定向到用户仪表板

与护照、mongodb 和 express 的持久会话