我正在使用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)
}
答案 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” 关键字:)