2012-06-22 8 views
5

Moduł uwierzytelniający "paszport" wymaga metody FindOrCreate w celu zalogowania. Używam mangusty, aby uratować moje użytkowników z następującym schematem:Jak radzić sobie z asynchronizacją. Metoda findOrCreate dla paszportu i mangusty

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

Tablica posiada rachunki obiektów, które reprezentują konta Facebook, jak {provider: "facebook", uid: "someFacebookId"}.

Moja strategia uwierzytelniania wygląda następująco:

// 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); 
      }); 
      } 
     }); 
    }); 
    } 
)); 

Problem: Po kwerend mojej bazy danych (User.find(...)) Funkcja zwrotna jest wykonywana natychmiast, nie czekając na moja baza odpowiedzieć. Powoduje to niezdefiniowanie obiektu. Dostaję dublikację tego samego użytkownika do mojej bazy danych za każdym razem, gdy ten użytkownik próbuje się zalogować.

Jak poprawnie obsłużyć to asynchroniczne wywołanie zwrotne?

+0

Wiem, że nie jest to bezpośrednio związane z pytaniem, ale czy nie jest to, że zapytanie jest trochę niebezpieczne? Poszukuje użytkownika z dowolnymi kontami o danej wartości iz każdym kontem. Dostarcza "facebook". Ale co zmusza ich do tego samego elementu listy kont? To znaczy, co jeśli inny użytkownik miał pasujący identyfikator uid z innym dostawcą? – StevenC

+0

Zakładam, że szuka kombinacji obu wartości, które powinny być unikalne. – Sven

+1

To założenie jest niebezpieczne. Ponieważ znalezienie w tablicy kont jest takie samo, jeśli użytkownik ma konto na Facebooku i konto * DOWOLNE * ma ten identyfikator. Jeśli ktoś ma serwer OpenAuth, może zalogować się jako dowolny użytkownik, zwracając numer, którego chciał. – tangxinfa

Odpowiedz

4

User.find zwraca tablicę dokumentów spełniających twoje warunki. W tym przypadku należy użyć wartości User.findOne, a następnie sprawdzić, czy if (olduser)... określa, czy znaleziono pasujący dokument.

+0

Dziękuję. To zajęło mi trochę czasu. Dziękuję :-) – Sven

+1

Przed wyjściem do produkcji warto zajrzeć do transakcji: http://www.mongodb.org/display/DOCS/two-phase+commit W przeciwnym razie dwa użytkownicy rejestrujący się w tym samym czasie przy użyciu tej samej nazwy użytkownika złamią system. Oczywiście nie za duży problem * po prostu * dla Facebooka, ponieważ nazwy użytkowników są już unikalne, ale będą odgrywać większą rolę, gdy rozszerzysz swój system uwierzytelniania o inne strategie. – 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

Niektóre wyjaśnienia na temat tego kodu byłyby miłe. –

+0

Najpierw przeszukujemy naszą bazę danych, jeśli jest tam stary użytkownik, jeśli istnieje stary użytkownik, który wywołujemy, a jeśli nie ma użytkownika w bazie danych, tworzymy nowego użytkownika i zapisujemy go w naszej bazie danych. – diesel

Powiązane problemy