为什么 Passport 在连接失败时重试身份验证?

Why does Passport retry the authentication when it fails to connect?

我有一个 Node.js & Express 应用程序,使用 Passport and passport-ldapauth 进行 LDAP 身份验证。

一切正常...除非无法连接到 LDAP 服务器(可能离线,或者 IP 地址错误等)。在那种情况下, passport.authenticate 以某种方式执行了两次(我只是不明白为什么),结果,我得到 Error: Can't set headers after they are sent.

这些是我的 server.js 和 routes.js 的相关部分:

// Import modules
var express      = require('express');
var session      = require('express-session');
var passport     = require('passport');
var passportLdap = require('passport-ldapauth');

// Configure Express, session suppport, and Passport
var app = express();
app.use(session({ resave: false, saveUninitialized: false, secret: 'foo' }));
passport.use('ldap', new passportLdap({server: { /* LDAP settings */ }}));
app.use(passport.initialize());
app.use(passport.session());

// Routings
app.get('/login', function(req, res) { res.render('loginForm.ejs'); });
app.post('/login', function(req, res) {
    passport.authenticate('ldap', {session: true}, function(err, user, info) {
        if (err || !user) {
            console.log(err ? 'ERROR' : 'CREDENTIALS');
            res.status(403).render('loginForm.ejs', {message: err || 'Wrong credentials!'});
        } else {
            console.log('SUCCESS');
            res.redirect('/home');
        }
    })(req, res);
});

如果认证成功,控制台只显示SUCCESS.

如果用户输入了错误的用户名或密码,它会显示 CREDENTIALS,并再次加载登录表单,显示 "Wrong credentials!" 消息。控制台上没有出现错误。

但是,如果 LDAP 服务器关闭,我在控制台 上得到 ERROR 两次。 (为什么?!)然后显然,当它用相同的响应 object 执行第二个 res.render 时,我得到了 Can't set headers after they are sent 错误。由于这是第二次尝试失败,用户仍然会获得带有正确错误消息(在第一次尝试时呈现)的表单登录。

如果我将 if (err) 块更改为执行 next(err) 而不是 res.render()... 我没有得到 headers 问题,但仍然是异常使用 LDAP(例如 "Error: getaddrinfo ENOTFOUND")在控制台上显示两次,就好像 Passport 在第一次尝试后重试一样。

此外,我注意到在 ldapauth 中有一个 handleErrorsAsFailures 选项。如果我启用它,那么它会在控制台上显示两次连接问题 CREDENTIALS,如果我输入了错误的凭据,它只会显示一次。

是什么导致了这个问题?

作为 (希望是暂时的?) 解决方法,我已将我的代码更改为:

if (err || !user) {
    if (!res.headersSent) { // <---------- CHECK TO PREVENT THE ISSUE ---------
        console.log(err ? 'ERROR' : 'CREDENTIALS');
        res.status(403).render('loginForm.ejs', {message: err || 'Wrong credentials!'});
    }
} else // ...

这会阻止第二次渲染尝试,并避免 Can't set headers after they are sent 错误。

我仍然不知道是什么导致了这种行为,也不知道如何解决它...

我的解决方法是用 if-else 语句包装路由中的所有代码:

    if(res.headersSent) {
       return;
    } else {
      *//the rest of the code goes here*
    }