Meteor 用户帐户问题 - 使用 OAuth 服务创建重复帐户 (accounts-google)

Meteor user accounts issue - Duplicate account being created with OAuth service (accounts-google)

我正在使用 Meteor 用户帐户创建用户。我实现了两种创建用户的方法。

  1. 通过使用accounts-password创建(默认一个)。
  2. OAuth 服务(accounts-googleaccounts-facebook

accounts-password生成的用户账户有如下文件

{
  "_id": "DQnDpEag2kPevSdJY",
  "createdAt": "2015-12-10T22:34:17.610Z",
  "services": {
    "password": {
      "bcrypt": "XXX"
    },
    "resume": {
      "loginTokens": [
        {
          "when": "2015-12-10T22:34:17.615Z",
          "hashedToken": "XXX"
        }
      ]
    }
  },
 -----
----
}

其中使用 accounts-google 或 account-facebook 生成的用户帐户具有如下所示的文件。

{
  "_id": "Ap85ac4r6Xe3paeAh",
  "createdAt": "2015-12-10T22:29:46.854Z",
  "services": {
    "facebook": {
      "accessToken": "XXX",
      "expiresAt": 1454970581716,
      "id": "XXX",
      "email": "myname@gmail.com",
      "name": "Ada Lovelace",
      "first_name": "Ada",
      "last_name": "Lovelace",
      "link": "https://www.facebook.com/app_scoped_user_id/XXX/",
      "gender": "female",
      "locale": "en_US",
      "age_range": {
        "min": 21
      }
    },
---
---
---

现在真正的问题是,尽管帐户密码和帐户-google 使用的电子邮件地址相同(在我的例子中电子邮件是 myname@gmail.com),但两个不同的用户帐户正在创建。

我正在寻找解决方案,如下所示。 (注意:服务在单个帐户下有 "Password" 和 "Facebook" 部分)

{
  "_id": "DQnDpEag2kPevSdJY",
  "createdAt": "2015-12-10T22:34:17.610Z",
  "services": {
    "password": {
      "bcrypt": "XXX"
    },
    "facebook": {
      "accessToken": "XXX",
      "expiresAt": 1454970581716,
      "id": "XXX",
      "email": "myname@gmail.com",
      "name": "Ada Lovelace",
      "first_name": "Ada",
      "last_name": "Lovelace",
      "link": "https://www.facebook.com/app_scoped_user_id/XXX/",
      "gender": "female",
      "locale": "en_US",
      "age_range": {
        "min": 21
      }
    },
  },
 -----
----
}

有没有办法在两种情况下都只生成一个帐户,这意味着如果用户已经存在并且正在尝试使用 OAuth 服务,则应该使用第一个帐户来容纳该服务?

您可以在服务器上使用 Accounts.setPassword 以便为帐户生成正确的 bcrypt 哈希:

Accounts.setPassword('Ap85ac4r6Xe3paeAh', 'the-new-password')

这将导致

{
  "_id": "Ap85ac4r6Xe3paeAh",
  "createdAt": "2015-12-10T22:29:46.854Z",
  "services": {
    "password": {
      "bcrypt": "b$nzHCivxVqxbuFBBPWewPPu.r5x7OR5gJB8PIklU4OoU.WK0MT8jt2"
    },
    "facebook": {
      "accessToken": "XXX",
      "expiresAt": 1454970581716,
      "id": "XXX",
      "email": "myname@gmail.com",
      "name": "Ada Lovelace",
      "first_name": "Ada",
      "last_name": "Lovelace",
      "link": "https://www.facebook.com/app_scoped_user_id/XXX/",
      "gender": "female",
      "locale": "en_US",
      "age_range": {
        "min": 21
      }
    }
  }
}

我已经通过 hack 解决了上述问题。

imports/startup/server/accounts.js 中,我添加了以下验证逻辑,它始终验证新创建的帐户。

想法是,此过程检查用户是否已存在于数据库中。如果用户存在,则进一步检查其创建自 accounts-passwordaccounts-google/facebook .

基于现有类型,用新字段修改现有字段,并抛出一条错误消息(这实际上会阻止创建新帐户)。

Accounts.validateNewUser(function (user) {

// first check what is the newly creating service
  var service =
    user.services.google || user.services.facebook || user.services.password;


  if (!service) return true;

  var existingUser = null;
// due to some issues both `Meteor.users.findOne(email)` as well `Account.findUserByEmail(email)` methods have been used to find the existing user status

  if (user.services.password) {
    var email = user.emails[0].address;
    existingUser = Meteor.users.findOne({
      $or: [
        { "registered_emails[0].address": email },
        { "services.google.email": email },
        { "services.facebook.email": email },
      ],
    });

  } else {
    var email = service.email;
    //console.log(" retrieved email ", email);
    existingUser = Accounts.findUserByEmail(email);
  }

  //console.log(" existingUser  : ", existingUser);
  if (!existingUser) return true;

  if (user.services.google) {
    Meteor.users.update(
      { _id: existingUser._id },
      {
        $set: {
          profile: user.profile,
          "services.google": user.services.google,
        },

      }
    );
  } else if (user.services.facebook) {
    Meteor.users.update(
      { _id: existingUser._id },
      {
        $set: {
          profile: user.profile,
          "services.facebook": user.services.facebook,
        },

      }
    );
  } else {
    Meteor.users.update(
      { _id: existingUser._id },
      {
        $set: {
          profile: user.profile,
          "services.password": user.services.password,
          "services.email": user.services.email,
          emails: user.emails,
        },

      }
    );
  }

  throw new Meteor.Error(
    205,
    "Merged with your existing Social Login accounts now. Try refresh the page and sign in again. That should work !!"
  );
});

link-accounts 套餐是允许用户向其帐户添加额外服务的推荐方式。