简体   繁体   English

如何在Node.js + MongoDB + PassportJS应用中执行异步身份验证

[英]How to do asynchronous authentication in Node.js + MongoDB + PassportJS app

I'm using Node.js, MongoDB, and PassportJS and I'm trying to authenticate using the local strategy (just simple id and password). 我正在使用Node.js,MongoDB和PassportJS,并且尝试使用本地策略(仅使用简单的ID和密码)进行身份验证。 The problem is that everything in Mongo is asynchronous, but Passport is synchronous. 问题在于,Mongo中的所有内容都是异步的,但是Passport是同步的。 I thought about trying to "hook" passport so that I could create my own callback to continue with authentication once the Mongo callbacks returned, but I don't know how the passport code works (and I'm not yet desperate enough to fire up a debugger and trace it). 我考虑过尝试“钩住”护照,以便我可以创建自己的回调,以便在Mongo回调返回后继续进行身份验证,但是我不知道护照代码的工作原理(而且我还不十分希望启动调试器并对其进行跟踪)。

The authentication process will actually finish successfully, but not before the app has responded to the client, causing the client to think it is still un-authenticated. 身份验证过程实际上将成功完成,但不是在应用程序对客户端做出响应之前完成,从而导致客户端认为它仍未经身份验证。 For example, after the client tries to authenticate, it is redirected back to the login form because the session isn't authenticated. 例如,在客户端尝试进行身份验证之后,由于未对会话进行身份验证,客户端将被重定向回登录表单。 If I then simply refresh the page, I get in because, by that point, the authentication callbacks have returned. 如果我然后仅刷新页面,我就会进入,因为到那时,身份验证回调已经返回。

passport.use(new localAuth(function(username, password, done)
{
    process.nextTick(function()
    {
        mc.connect('mongodb://127.0.0.1:27017/example', function(err, db)
        {
            if(err)
                throw err;

            db.collection('users').findOne({GUID: username}, function(err, results)
            {
                if(err)
                    throw err;
                console.log('Here I am!');
                db.close();
                return done(null, username);
            });
        });
    });
}));

(I realize the above code is not authenticating anything. I'm just trying to work through the asynchronous approach.) (我意识到上面的代码没有对任何内容进行身份验证。我只是在尝试通过异步方法进行工作。)

I've tried multiple different variations on the above, but they all suffer from the same issue: the function given to localAuth() returns and passport proceeds with authentication before my database lookup has a chance to complete. 我已经在上面尝试了多种不同的变体,但是它们都遇到了相同的问题:在我的数据库查找有机会完成之前,赋予localAuth()的函数会返回,并且护照会继续进行身份验证。 I've seen several questions on SO about trying to force mongo to work synchronously and the responses are all "don't" . 我已经在SO上看到了几个有关试图迫使mongo同步工作的问题,而这些响应都是“不”的 I saw this question , which is exactly my scenario and my approach is the same, but I still have the issue of needing to refresh after the callbacks return. 我看到了这个问题 ,这确实是我的情况,并且我的方法是相同的,但是仍然存在在回调返回后需要刷新的问题。

How should I perform authentication in a node.js + mongoDB + passport app? 我应该如何在node.js + mongoDB + Passport应用程序中执行身份验证?

UPDATE I have noticed that 'Here I am!' 更新我注意到“我在这里!” appears in the log during the first attempt (ie. prior to refreshing the page). 在第一次尝试期间(即在刷新页面之前)出现在日志中。 That makes me think that authentication is finishing and the session is set during the first authentication attempt. 这使我认为身份验证已完成,并且在第一次身份验证尝试期间设置了会话。 Just whatever is being returned from localAuth() 's callback ( done() ) isn't making it in time. 只是从localAuth()的回调( done() )返回的任何内容都不及时。 Then when I refresh, passport tries to get the session and sees that it's there. 然后,当我刷新时,passport会尝试获取会话并看到它在那里。 This brings me back to trying to hook passport. 这使我重新尝试钩住护照。 Does anyone know when new localAuth() gets called during authentication? 有人知道身份验证期间何时调用new localAuth()吗?

UPDATE UPDATE

function authenticateUser(id, pass, cb)
{
console.log('1');
    mc.connect('mongodb://127.0.0.1:27017/sp2010sec', function(err, db)
    {
        if(err)
            throw err;

console.log('2');
        db.collection('users').findOne({GUID: id}, function(err, results)
        {
            if(err)
                throw err;
console.log('3');

            return cb(err, id);
        });
console.log('4');
    });
console.log('5');
}

passport.use(new localAuth(function(username, password, done)
{
console.log('6');
    authenticateUser(username, password, function(err, user)
    {
console.log('7');
        return done(err, username);
    });
console.log('8');
}));

The above code produces this log: 上面的代码生成此日志:

6 6

1 1

5

8 8

2 2

4 4

3 3

7 7

Passport does not appear to be waiting for done to be called. 护照似乎没有等待done呼叫。

I've gotten a band-aid over the asynchronous authentication, so I'll explain what I did. 我已经获得了异步身份验证的创可贴,所以我将解释我的工作。 If anyone can give a better answer, I'd love to hear it. 如果有人能给出更好的答案,我很想听听。

So, the problem is that mongoDB is asynchronous, but passport is not and everything I could think of resulted in passport authenticating the request (or failing to, rather) before the mongo callbacks had returned. 因此,问题在于mongoDB是异步的,但不是护照,而我能想到的一切都会导致护照在mongo回调返回之前对请求进行身份验证(或者失败)。 I tried multiple approaches to hooking passport so that I didn't even start the passport authentication until I had the mongo stuff done (sort of pre-authentication), but that didn't work either. 我尝试了多种方法来钩挂护照,以便直到完成mongo内容(某种预身份验证)后,我才开始进行护照身份验证,但是那也不起作用。 I'm assuming that has to do with the internals of passport. 我认为这与护照的内部情况有关。

What I ended up doing was opening the db connection at app startup and leaving it open for the life of the app. 我最终要做的是在应用程序启动时打开数据库连接,并在应用程序的整个生命周期中保持打开状态。 This cuts down on one callback and I think this is letting the mongo callbacks finish in time for passport to see it. 这减少了一个回调,我认为这是让mongo回调及时完成,以便护照可以看到它。 This feels like a potential race condition. 这感觉像是潜在的比赛条件。 I would love to see a better answer than this or an explanation as to what's really happening. 我希望看到一个比这个更好的答案,或者对真实情况进行解释。

UPDATE UPDATE

The real problem was that I wasn't using passport's success/failure redirects; 真正的问题是我没有使用护照的成功/失败重定向。 I was handling that on the client side, which started as soon as the AJAX call returned (but was not involved in the passport callback chain). 我在客户端处理此问题,该客户端在AJAX调用返回时就开始了(但未涉及护照回调链)。 Once I started handling the redirects on the server side, the authentication started working as expected/advertised. 一旦我开始在服务器端处理重定向,身份验证就开始按预期/通告的方式工作。

I don't think you want to have your user lookup wrapped in a process.nextTick() call. 我不认为您希望将用户查找包裹在process.nextTick()调用中。 According to this answer , you only want to use nextTick() when you want that code to be called on the next iteration of the event loop. 根据此答案 ,您只想在事件循环的下一次迭代中调用该代码时才使用nextTick() Simply removing that should fix the issue. 只需将其删除即可解决问题。 This is similar to the code posted on the guide for passport.js. 这类似于发布在passport.js 指南上的代码。

Hope this helps! 希望这可以帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM