2012-06-22 6 views
5

Модуль аутентификации 'Passport' требует метода FindOrCreate для входа в систему. Я использую мангуст, чтобы спасти свои пользователь со следующей схемой:Как бороться с async. findOrCreate метод для паспорта и mongoose

var UserSchema = new Schema({ 
    firstname: String, 
    lastname: String, 
    email: String, 
    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. Поэтому я получаю дубликат одного и того же пользователя в моей базе данных каждый раз, когда этот пользователь пытается войти в систему.

Как правильно обрабатывать этот асинхронный обратный вызов?

+0

Я знаю, что это напрямую не связано с вопросом, но разве это не так, что найти запрос немного опасно? Он ищет пользователя с любыми accounts.uid данного значения и с любым accounts.provider из 'facebook'. Но что заставляет их быть одним и тем же элементом списка счетов? То есть, что, если у другого пользователя был соответствующий uid с другим провайдером? – StevenC

+0

Я предполагаю, что он ищет комбинацию обоих значений, которая должна быть уникальной. – Sven

+1

Это предполагает опасность. Поскольку поиск в массиве учетных записей согласован, если у пользователя есть учетная запись facebook, а учетная запись * ANY * имеет этот uid. Если у кого-то есть сервер OpenAuth, он может войти в систему как любой пользователь, вернув ему uid. – tangxinfa

ответ

4

User.find возвращает массив документов, соответствующих вашим условиям. В вашем случае вы хотите вместо этого использовать User.findOne, а затем отметьте if (olduser)..., чтобы определить, был ли найден соответствующий документ.

+0

Спасибо. Это заняло у меня время. Спасибо :-) – Sven

+1

Перед тем, как приступить к производству, вы захотите ознакомиться с транзакциями: http://www.mongodb.org/display/DOCS/two-phase+commit В противном случае два пользователи, регистрирующиеся одновременно с одним и тем же именем пользователя, будут разбивать систему. Очевидно, что не слишком много проблем * просто * для facebook, поскольку имена пользователей уже уникальны, но они будут играть большую роль, поскольку вы увеличиваете свою систему аутентификации другими стратегиями. – mikermcneil

1
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); 
      }); 
     } 
     }); 
    }); 
+2

Некоторые объяснения по поводу этого кода были бы приятными. –

+0

сначала мы запрашиваем нашу базу данных, если есть oldUser, если есть oldUser, который мы вызываем, и если в базе данных нет пользователя, мы создаем нового пользователя и сохраняем его в нашей базе данных. – diesel

3

Hate придираться, но и другие методы, упомянутые здесь, сломаться, если два пользователя пытаются подписаться на тот же time--, прежде чем идти в производство, вы хотите, чтобы посмотреть в сделок: http://www.mongodb.org/display/DOCS/two-phase+commit

 Смежные вопросы

  • Нет связанных вопросов^_^