为我的应用程序创建了个人资料页面后,我想显示用户所在的社交服务列表。令我震惊的是,最简单的方法是为此使用 Meteor 的内置帐户系统。
有没有向现有帐户添加外部服务的好方法?
此外,用户是否可以使用我的应用程序中的任何一个(例如)Facebook和他的密码登录?
另一个自然而然的问题是:有没有一种好方法可以将特定于应用程序的密码添加到使用外部服务创建的帐户中?
为我的应用程序创建了个人资料页面后,我想显示用户所在的社交服务列表。令我震惊的是,最简单的方法是为此使用 Meteor 的内置帐户系统。
有没有向现有帐户添加外部服务的好方法?
此外,用户是否可以使用我的应用程序中的任何一个(例如)Facebook和他的密码登录?
另一个自然而然的问题是:有没有一种好方法可以将特定于应用程序的密码添加到使用外部服务创建的帐户中?
这是另一种方法。在这个解决方案中,我重写了一个核心函数并添加了一些自定义行为。我的目标是将服务数据与当前登录的用户相关联,然后让核心功能像往常一样做它的事情。
orig_updateOrCreateUserFromExternalService = Accounts.updateOrCreateUserFromExternalService;
Accounts.updateOrCreateUserFromExternalService = function(serviceName, serviceData, options) {
var loggedInUser = Meteor.user();
if(loggedInUser && typeof(loggedInUser.services[serviceName]) === "undefined") {
var setAttr = {};
setAttr["services." + serviceName] = serviceData;
Meteor.users.update(loggedInUser._id, {$set: setAttr});
}
return orig_updateOrCreateUserFromExternalService.apply(this, arguments);
}
优点:
缺点:
这是我向现有用户帐户添加凭据的方法:.../meteor-how-to-login-with-github-account.html
是的,一个用户帐户可以与多个服务相关联,并同时具有基于密码的登录。在Meteor 文档中,您可以看到这样一个用户帐户的结构:
{
_id: "bbca5d6a-2156-41c4-89da-0329e8c99a4f", // Meteor.userId()
username: "cool_kid_13", // unique name
emails: [
// each email address can only belong to one user.
{ address: "cool@example.com", verified: true },
{ address: "another@different.com", verified: false }
],
createdAt: 1349761684042,
profile: {
// The profile is writable by the user by default.
name: "Joe Schmoe"
},
services: {
facebook: {
id: "709050", // facebook id
accessToken: "AAACCgdX7G2...AbV9AZDZD"
},
resume: {
loginTokens: [
{ token: "97e8c205-c7e4-47c9-9bea-8e2ccc0694cd",
when: 1349761684048 }
]
}
}
}
要将用户名/密码登录添加到现有帐户,您可以Accounts.sendResetPasswordEmail
在服务器端使用。这也确保更改发生经过身份验证和授权。
当然,您也可以自己使用新密码更新服务器端的用户记录,但这可能会在您的应用程序中造成安全漏洞。如果可能的话,我还建议不要为此实施自己的加密协议,因为这很难。
如果您想添加电子邮件以外的其他服务,例如,您可以
Accounts.loginWith[OtherService]
。这会使用其他服务上的新帐户将用户注销并再次登录。查看此帖子中的示例和答案。它几乎为您提供了集成多个外部和内部帐户的代码。通过细微的调整,您可以根据需要为每个帐户添加密码字段。
如何使用 Meteor.loginWithGoogle 与 mrt:accounts-ui-bootstrap-dropdown
代码:
isProdEnv = function () {
if (process.env.ROOT_URL == "http://localhost:3000") {
return false;
} else {
return true;
}
}
Accounts.loginServiceConfiguration.remove({
service: 'google'
});
Accounts.loginServiceConfiguration.remove({
service: 'facebook'
});
Accounts.loginServiceConfiguration.remove({
service: 'twitter'
});
Accounts.loginServiceConfiguration.remove({
service: 'github'
});
if (isProdEnv()) {
Accounts.loginServiceConfiguration.insert({
service: 'github',
clientId: '00000',
secret: '00000'
});
Accounts.loginServiceConfiguration.insert({
service: 'twitter',
consumerKey: '00000',
secret: '00000'
});
Accounts.loginServiceConfiguration.insert({
service: 'google',
appId: '00000',
secret: '00000'
});
Accounts.loginServiceConfiguration.insert({
service: 'facebook',
appId: '00000',
secret: '00000'
});
} else {
// dev environment
Accounts.loginServiceConfiguration.insert({
service: 'github',
clientId: '11111',
secret: '11111'
});
Accounts.loginServiceConfiguration.insert({
service: 'twitter',
consumerKey: '11111',
secret: '11111'
});
Accounts.loginServiceConfiguration.insert({
service: 'google',
clientId: '11111',
secret: '11111'
});
Accounts.loginServiceConfiguration.insert({
service: 'facebook',
appId: '11111',
secret: '11111'
});
}
Accounts.onCreateUser(function (options, user) {
if (user.services) {
if (options.profile) {
user.profile = options.profile
}
var service = _.keys(user.services)[0];
var email = user.services[service].email;
if (!email) {
if (user.emails) {
email = user.emails.address;
}
}
if (!email) {
email = options.email;
}
if (!email) {
// if email is not set, there is no way to link it with other accounts
return user;
}
// see if any existing user has this email address, otherwise create new
var existingUser = Meteor.users.findOne({'emails.address': email});
if (!existingUser) {
// check for email also in other services
var existingGitHubUser = Meteor.users.findOne({'services.github.email': email});
var existingGoogleUser = Meteor.users.findOne({'services.google.email': email});
var existingTwitterUser = Meteor.users.findOne({'services.twitter.email': email});
var existingFacebookUser = Meteor.users.findOne({'services.facebook.email': email});
var doesntExist = !existingGitHubUser && !existingGoogleUser && !existingTwitterUser && !existingFacebookUser;
if (doesntExist) {
// return the user as it came, because there he doesn't exist in the DB yet
return user;
} else {
existingUser = existingGitHubUser || existingGoogleUser || existingTwitterUser || existingFacebookUser;
if (existingUser) {
if (user.emails) {
// user is signing in by email, we need to set it to the existing user
existingUser.emails = user.emails;
}
}
}
}
// precaution, these will exist from accounts-password if used
if (!existingUser.services) {
existingUser.services = { resume: { loginTokens: [] }};
}
// copy accross new service info
existingUser.services[service] = user.services[service];
existingUser.services.resume.loginTokens.push(
user.services.resume.loginTokens[0]
);
// even worse hackery
Meteor.users.remove({_id: existingUser._id}); // remove existing record
return existingUser; // record is re-inserted
}
});