如何处理异步。护照和猫鼬的 findOrCreate 方法

Posted

技术标签:

【中文标题】如何处理异步。护照和猫鼬的 findOrCreate 方法【英文标题】:How to deal with async. findOrCreate method for passport and mongoose 【发布时间】:2012-06-24 16:30:59 【问题描述】:

身份验证模块“Passport”需要 FindOrCreate 方法才能进行登录。我正在使用猫鼬来使用以下架构保存我的用户:

var UserSchema = new Schema(
    firstname: String,
    lastname: String,
    email: String,
    accounts: []
);

accounts 数组包含代表 facebook 帐户的对象,例如 provider: "facebook", uid: "someFacebookId"

我的身份验证策略如下所示:

// Authentication Strategy
passport.use(new FacebookStrategy(
    clientID: CONFIG.fb.appId,
    clientSecret: CONFIG.fb.appSecret,
    callbackURL: CONFIG.fb.callbackURL
  ,
  function(accessToken, refreshToken, profile, done) 
    // asynchronous verification, for effect...
    process.nextTick(function () 

      User.find( 'accounts.uid': profile.id, 'accounts.provider': 'facebook' , function(err, olduser) 

          if(olduser._id) 
            console.log('User: ' + olduser.firstname + ' ' + olduser.lastname + ' found and logged in!');
            done(null, olduser);
           else 
            var newuser = new User();
            var account = provider: "facebook", uid: profile.id;
            newuser.accounts.push(account);
            newuser.firstname = profile.name.givenName;
            newuser.lastname = profile.name.familyName;
            newuser.email = "TBD...";

            newuser.save(function(err) 
              if(err)  throw err; 
              console.log('New user: ' + newuser.firstname + ' ' + newuser.lastname + ' created and logged in!');
              done(null, newuser);
            );
          
        );
    );
  
));

问题: 查询我的数据库 (User.find(...)) 后,回调函数立即执行,无需等待我的数据库响应。这会导致未定义的olduser 对象。因此,每次该用户尝试登录时,我都会将同一用户的副本复制到我的数据库中。

如何正确处理这个异步回调?

【问题讨论】:

我知道这与问题没有直接关系,但是 find 查询不是有点危险吗?它查找具有给定值的任何accounts.uid 和任何accounts.provider 'facebook' 的用户。但是是什么迫使它们成为相同的帐户列表元素?也就是说,如果另一个用户的 uid 与不同的提供者匹配呢? 我假设它正在寻找两个值的组合,这应该是唯一的。 这种假设是危险的。因为如果用户有 facebook 帐户并且 ANY 帐户具有该 uid,则在匹配的帐户数组中查找。如果某人有一个 OpenAuth 服务器,那么他可以通过返回他想要的 uid 以任何用户身份登录。 【参考方案1】:

User.find 返回一个 array 符合您的条件的文档。在您的情况下,您想改用 User.findOne,然后检查 if (olduser)... 以确定是否找到了匹配的文档。

【讨论】:

谢谢。这花了我一段时间。谢谢:-) 请注意,在投入生产之前,您需要查看交易:mongodb.org/display/DOCS/two-phase+commit 否则,使用相同用户名同时注册的两个用户会破坏系统。显然,对于 facebook,只是 不是太大的问题,因为用户名已经是独一无二的,但是当您使用其他策略增强身份验证系统时,它将发挥更多作用。【参考方案2】:

讨厌吹毛求疵,但如果两个用户尝试同时注册,这里提到的其他方法就会失效——在您投入生产之前,您需要查看交易:http://www.mongodb.org/display/DOCS/two-phase+commit

【讨论】:

【参考方案3】:
process.nextTick(function () 
      var query = User.findOne( 'fbId': profile.id );
      query.exec(function (err, oldUser) 
        console.log(oldUser);
        if(oldUser) 
          console.log('User: ' + oldUser.name + ' found and logged in!');
          done(null, oldUser);
         else 
          var newUser = new User();
          newUser.fbId = profile.id;
          newUser.name = profile.displayName;
          newUser.email = profile.emails[0].value;

          newUser.save(function(err) 
            if(err) throw err;
            console.log('New user: ' + newUser.name + ' created and logged in!');
            done(null, newUser);
          ); 
        
      );
    );

【讨论】:

首先我们查询我们的数据库是否有 oldUser,如果有 oldUser 我们调用 done,如果数据库中没有用户我们创建一个新用户并将其保存到我们的数据库中。跨度> 【参考方案4】:

有一个应用程序:mongoose-findorcreate

【讨论】:

以上是关于如何处理异步。护照和猫鼬的 findOrCreate 方法的主要内容,如果未能解决你的问题,请参考以下文章

本地护照和本地护照猫鼬的身份验证错误

在express中的每个数组元素中进行猫鼬查询时如何处理异步?

使用异步 javascript 和猫鼬连接性能表

使用猫鼬的异步函数中的返回类型会产生错误

连接停止时如何处理猫鼬数据库

从 JSON + Swift 或 ObjC 检索数据时如何处理 CoreData 中的关系