Meteor 用户帐户问题 - 使用 OAuth 服务创建重复帐户 (accounts-google)
Meteor user accounts issue - Duplicate account being created with OAuth service (accounts-google)
我正在使用 Meteor 用户帐户创建用户。我实现了两种创建用户的方法。
- 通过使用accounts-password创建(默认一个)。
- OAuth 服务(accounts-google 和 accounts-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-password
或 accounts-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 套餐是允许用户向其帐户添加额外服务的推荐方式。
我正在使用 Meteor 用户帐户创建用户。我实现了两种创建用户的方法。
- 通过使用accounts-password创建(默认一个)。
- OAuth 服务(accounts-google 和 accounts-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-password
或 accounts-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 套餐是允许用户向其帐户添加额外服务的推荐方式。