仅在发生错误时才调用passport.authenticate()两次

时间:2019-02-07 10:25:09

标签: javascript node.js express passport.js

我正在使用Ldap身份验证来验证用户。在成功的身份验证期间或当用户提供不正确的凭据时,此方法可以正常工作。但是,如果抛出错误,password.authenticate()函数将被调用两次,而我得到以下错误。

_http_outgoing.js:470
throw new ERR_HTTP_HEADERS_SENT('set');
^

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the 
client

那么为什么为什么仅在错误时才会调用passport.authenticate函数两次?以下是用于身份验证的代码。

let callCnt = 0

function pPortAuth(req,res,next) {
//Fetch the roles of the gid from the database
console.log("Called Here")
passport.authenticate('ldapauth', { session: false }, function (err, user, 
info) {
    console.log("Hetre " + req.method)
    ++callCnt
    console.log(callCnt)

    if (err || !user) {
        if (err && (err.code == 'ETIMEDOUT' || err.code == 'ENOTFOUND')) {
            console.log("Could not reach Ldap Server" + err.code)

            return res.status(400).json({ success: false, message: 'Could 
    not reach Ldap Server' })
        }else if(!user){
            console.log("Authentication Failed or not a valid user")
        return res.status(400).json({ success: false, message: 
   'Authentication Failed' });
        }
    }

    let roles = (user.sAMAccountName == 'g705615')?['readWrite']: 
    ['readOnly']
    console.log(roles)
    return res.send({
        success: true,
        gid: user.sAMAccountName,
        name: user.name,
        token: jwt.sign({ sub: user.sAMAccountName, roles: roles, 
   loggedInUsername: user.name }, config.secret)
    });
})(req,res,next)
}

下面是日志

Called Here
Hetre POST
1
Could not reach Ldap ServerENOTFOUND
Hetre POST
2
Could not reach Ldap ServerENOTFOUND

如果看到函数function pPortAuth(req,res,next)仅被调用一次,而passport.authenticate()函数则在出错时被调用两次。

谁能告诉我我在哪里犯错

更新

//users.controller.js
let express = require('express');
let userAuth = express.Router();
let expressJwt = require('express-jwt');
let passport = require('passport') 
let config = require("../config.json")
let userAuthSvc = require('../_services/user.service')

let Ldap = require('../config/ldap.config');

passport.serializeUser((user, done) => {
done(null,user)
})
passport.deserializeUser((user,done) => {
done(null,user)
})

passport.use(Ldap)

let initializePport = passport.initialize();

//userAuth.use(userAuthSvc.pportInit);
userAuth.post('/ldapLogin',initializePport, authenticate)

function authenticate (req, res, next) {
userAuthSvc.pportAuth(req, res, next);
}

//user.service.js
let passport = require('passport') 

function pPortAuth(req,res,next) {
//Fetch the roles of the gid from the database
console.log("Called Here")
passport.authenticate('ldapauth', { session: false }, function (err, user, 
info) {
    console.log("Hetre " + req.method)
    ++callCnt
    console.log(callCnt)

    if (err || !user) {
        if (err && (err.code == 'ETIMEDOUT' || err.code == 'ENOTFOUND')) {
            console.log("Could not reach Ldap Server" + err.code)

            return res.status(400).json({ success: false, message: 'Could 
  not reach Ldap Server' })
        }else if(!user){
            console.log("Authentication Failed or not a valid user")
        return res.status(400).json({ success: false, message: 
 'Authentication Failed' });
        }
    }

    let roles = (user.sAMAccountName == 'g705615')?['readWrite']: 
 ['readOnly']
    console.log(roles)
    return res.send({
        success: true,
        gid: user.sAMAccountName,
        name: user.name,
        token: jwt.sign({ sub: user.sAMAccountName, roles: roles, 
 loggedInUsername: user.name }, config.secret)
    });
 })(req,res,next)
 }

3 个答案:

答案 0 :(得分:1)

您可以从您的策略中多次接到护照。 检查您的策略函数内部的回调,并且内部用户验证函数仅回调一次。

对我来说,我忘记了将return放在用户名db查找函数中的一个回调前面,导致了两个回调。

function strategy(username, password, cb) {
    getEmailFromDB(username, async (err, user) => {
        console.log('stragegy res',err,user);
        if (err) { 
            console.log('lookup error',err);
            return cb(err);
        }
        if (!user) { 
            console.log('bad username');
            return cb(null, false); 
        }
        ...


function getEmailFromDB(id, cb) {
    process.nextTick(async () => {
        try {
            var account = await r.table('users').get(id).run(rconn)
            if(!account) {
                console.log('User doesnt exist',id);
                return cb(true);                       // had forgot return here
            }
            cb(null, {
                'id'        : account.id,
                'name'      : account.name,
                'password'  : account.password,
                'roles'     : account.roles 
            });
        } catch (e) {
            console.log('Lookup error for user',id);
            cb(true);
        }
    });
}

答案 1 :(得分:0)

我可以针对我的问题提出的唯一解决方法是防止将响应发送两次。 我认为的问题是,当passport.authenticate()函数遇到错误ENOTFOUND时,它将再次调用回调,因为我认为处理不正确。因此,要克服此问题,我只需检查一下是否已经发送了标头,如果是,则从函数返回,否则发送响应。以下是我的代码,如果需要任何帮助,请对其进行评论。

app.post('/ldapLogin', function (req, res, next) {
passport.authenticate('ldapauth', { session: false }, function (err, user, info) {

    let resObj = {}
    let resStatus 
    if (err || !user) {
        if (err && (err.code == 'ETIMEDOUT' || err.code == 'ENOTFOUND')) {
            resStatus = res.status(400)
            resObj['success'] = false
            resObj['message'] = 'Could not reach Ldap Server'

        }else if(!user){
            console.log("Authentication Failed or not a valid user")
            resStatus = res.status(400)
            resObj['success'] = false
            resObj['message'] = 'Authentication Failed'
        }
    }else{
        resStatus = res
        let roles = (user.sAMAccountName == 'xxxxx')?['readWrite']:['readOnly']
        resObj['success'] = true
        resObj['gid'] = user.sAMAccountName
        resObj['name'] = user.name
        resObj['token'] = jwt.sign({ sub: user.sAMAccountName, roles: roles, loggedInUsername: user.name }, config.secret)
    } 
    if(res.headersSent)
    return
    return resStatus.send(resObj);
})(req, res, next)
})

答案 2 :(得分:0)

我也遇到了这个问题,并通过更改错误处理程序中间件以强制停止请求的进行来解决了该问题。实际上,错误处理程序中间件必须停止请求。

拧紧错误处理程序中间件:

export const errorHandler = (err, req, res, next) => {
    console.error(err);
    res.status(400).send({errors: [{message: 'Something went wrong.'}]});
};

正确的错误处理程序中间件:

export const errorHandler = (err, req, res, next) => {
    console.error(err);
    return res.status(400).send({errors: [{message: 'Something went wrong.'}]});
};

区别只是一个简单的“ return” 关键字:)