2012-06-22 24 views
5

Mô-đun xác thực 'Hộ chiếu' yêu cầu phương thức FindOrCreate để đăng nhập. Tôi đang sử dụng mongoose để tiết kiệm người dùng của tôi với sơ đồ sau:Cách xử lý async. Phương thức findOrCreate cho hộ chiếu và mongoose

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

Mảng tài khoản giữ đối tượng đại diện cho tài khoản facebook, như {provider: "facebook", uid: "someFacebookId"}.

chiến lược xác thực của tôi trông như thế này:

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

Vấn đề: Sau khi truy vấn cơ sở dữ liệu của tôi (User.find(...)) chức năng gọi lại được thực hiện ngay lập tức mà không cần chờ cho cơ sở dữ liệu của tôi để trả lời. Điều này dẫn đến một đối tượng không xác định olduser. Vì vậy, tôi nhận được một cộng hòa của cùng một người dùng vào cơ sở dữ liệu của tôi mỗi khi người dùng này cố gắng đăng nhập.

Làm cách nào để xử lý cuộc gọi lại không đồng bộ này một cách chính xác?

+0

Tôi biết điều này không liên quan trực tiếp đến câu hỏi, nhưng không phải là tìm truy vấn có chút nguy hiểm không? Nó tìm kiếm một người dùng với bất kỳ accounts.uid nào của giá trị đã cho và với bất kỳ accounts.provider nào của 'facebook'. Nhưng điều gì buộc họ phải là cùng một yếu tố danh sách tài khoản? Đó là, nếu một người dùng khác có một uid phù hợp với một nhà cung cấp khác thì sao? – StevenC

+0

Tôi giả sử nó đang tìm kiếm sự kết hợp của cả hai giá trị, mà nên là duy nhất. – Sven

+1

Giả định này là nguy hiểm. Bởi vì tìm trong mảng tài khoản phù hợp nếu người dùng có tài khoản facebook và tài khoản * BẤT K * * có uid. Nếu ai đó có một máy chủ OpenAuth, sau đó ông có thể đăng nhập như bất kỳ người dùng bằng cách trả lại uid ông muốn. – tangxinfa

Trả lời

4

User.find trả về một mảng tài liệu khớp với điều kiện của bạn. Trong trường hợp của bạn, bạn muốn sử dụng User.findOne để thay thế, sau đó kiểm tra if (olduser)... để xác định xem một tài liệu phù hợp đã được tìm thấy chưa.

+0

Cảm ơn bạn. Điều đó đã cho tôi một lúc rồi. Cảm ơn bạn :-) – Sven

+1

Cảnh báo trước khi bạn đi vào sản xuất, bạn sẽ muốn xem giao dịch: http://www.mongodb.org/display/DOCS/two-phase+commit Nếu không, hai người dùng đăng ký cùng lúc với cùng tên người dùng sẽ phá vỡ hệ thống. Rõ ràng không quá nhiều vấn đề * chỉ * đối với facebook, vì tên người dùng đã là duy nhất, nhưng nó sẽ đóng vai trò nhiều hơn khi bạn tăng cường hệ thống xác thực của mình với các chiến lược khác. – 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

Một số giải thích về mã này sẽ rất hay. –

+0

đầu tiên chúng ta truy vấn cơ sở dữ liệu của chúng ta nếu có một oldUser, nếu có một oldUser chúng ta gọi là xong và nếu không có user trong database chúng ta tạo một user mới và lưu nó vào database của chúng ta. – diesel

3

Ghét để nitpick, nhưng các phương pháp khác được đề cập ở đây phá vỡ nếu hai người dùng thử đăng ký tại time-- cùng trước khi bạn đi vào sản xuất, bạn sẽ muốn có một cái nhìn vào giao dịch: http://www.mongodb.org/display/DOCS/two-phase+commit

Các vấn đề liên quan