I am setting up a meteor app that involves signing up with a username and password, then hopefully connecting that account with facebook and twitter.
I have the first part up and running easily, just with the accounts package. But when I have a logged in user call Meteor.loginWithFacebook(), it logs them out and creates a new account. What I want is something that adds the facebook credentials to the currently logged in user.
The meteor docs have this:
{
_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: Wed Aug 21 2013 15:16:52 GMT-0700 (PDT),
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 }
]
}
}
}
which appears to be an account with a username that's also authenticated with Facebook. But I'm not sure if that's just an example that you can't actually achieve with basic Meteor stuff.
What I am trying to make is basically
Meteor.connectWithExternalAccount();
which runs the same process as Meteor.loginWithExternalAccount(), but just adds the information to the currently logged in user.
If someone could just explain the accounts-base package a bit so I could know where to start for myself that would be great.
Also, does anyone know if this will be included in any future versions of Meteor?
So there's been work to solve this problem, but unfortunately the pull request https://github.com/meteor/meteor/pull/1133 never got merged. Probably your best bet is check the meteor-core Google Groups and see if there was any comment on it and if not, see if you can get a core dev to comment on it.
If you want to still use the pull request, what you could do is remove the various Meteor accounts-*
packages, then in the root of your project, create a /packages
folder and copy yubozhao's patched accounts-*
packages in there (probably smart to append -custom
). You'd then meteor add accounts-base-custom
, etc. to add them to your project.
Note though, yubozhao wrote this is 6-7 months ago and you may need to stick with whatever version of Meteor that was current then for it to work.
Update April 2014: There's an Atmosphere package now that has a similar use case that might be useful: https://atmospherejs.com/package/accounts-merge
Here is a code that worked for me ( inside server folder ):
Accounts.onCreateUser(function(options, user) {
var email, oldUser, service;
/*
user.groups = {
created: "",
invited:"",
RSVP:{
coming:"",
notComing:"",
noReplay:""
}
};
*/
if (user.profile == null) {
user.profile = options.profile
}
if (user.services != null) {
service = _.keys(user.services)[0];
email = user.services[service].email;
if (email != null) {
oldUser = Meteor.users.findOne({
"emails.address": email
});
if (oldUser != null) {
if (oldUser.services == null) {
oldUser.services = {};
}
if (service === "google" || service === "facebook") {
oldUser.services[service] = user.services[service];
Meteor.users.remove(oldUser._id);
user = oldUser;
}
} else {
if (service === "google" || service === "facebook") {
if (user.services[service].email != null) {
user.emails = [
{
address: user.services[service].email,
verified: true
}
];
} else {
throw new Meteor.Error(500, "" + service + " account has no email attached");
}
user.profile.name = user.services[service].name;
}
}
}
}
return user;
});
userAddOauthCredentials: function(token, userId, service) {
var data, oldUser, selector, updateSelector;
switch (service) {
case "facebook":
data = Facebook.retrieveCredential(token).serviceData;
break;
case "google":
data = Google.retrieveCredential(token).serviceData;
}
selector = "services." + service + ".id";
oldUser = Meteor.users.findOne({
selector: data.id
});
if (oldUser != null) {
throw new Meteor.Error(500, ("This " + service + " account has already") + "been assigned to another user.");
}
updateSelector = "services." + service;
Meteor.users.update(userId, {
$set: {
updateSelector: data
}
});
if (!_.contains(Meteor.user().emails, data.email)) {
return Meteor.users.update(userId, {
$push: {
"emails": {
address: data.email,
verified: true
}
}
});
}
}
inside client js folder :
var addUserService;
addUserService = function(service) {
if (service === "email") {
} else {
switch (service) {
case "facebook":
return Facebook.requestCredential({
requestPermissions: ["email", "user_friends", "manage_notifications"]
}, function(token) {
return Meteor.call("userAddOauthCredentials", token, Meteor.userId(), service, function(err, resp) {
if (err != null) {
return Meteor.userError.throwError(err.reason);
}
});
});
case "google":
return Google.requestCredential({
requestPermissions: ["email", "https://www.googleapis.com/auth/calendar"],
requestOfflineToken: true
}, function(token) {
return Meteor.call("userAddOauthCredentials", token, Meteor.userId(), service, function(err, resp) {
if (err != null) {
return Meteor.userError.throwError(err.reason);
}
});
});
}
}
};
same js file inside template events:
"click a": function(e) {
var service;
e.preventDefault();
service = $(event.target).data("service");
return addUserService(service);
}
and for the html just done this:
<div class="social"><a id="fb" data-service="facebook"><img src="/../facebook.png"></a></div>
<div class="social"><a id="go" data-service="google"><img src="/../googleplus.png"></a></div>
mainly you need to have the data-service set to your service, then the template click event takes the data-service and execute the addUserService(data-passed).
hope it will work, please let me know.
来源:https://stackoverflow.com/questions/20391689/connect-service-to-existing-meteor-account