我想出了一个更好的方法来做到这一点,而不使用accounts-facebook并且不使用facebook自己的sdk但是我使用meteor的帐户和account-ui(不是我真的需要它,它只是方便)
客户端上的事件处理程序
Template.header.events({
'click #loginFB': function(e) {
e.preventDefault();
OAuth.redirect('facebook', "/oauthlink");
//or
var url = 'https://www.facebook.com/dialog/oauth?client_id=' +client_id+'&response_type=token&redirect_uri='+redirect;
window.location = url;
}
});
从 OAuth 捕获结果的 Iron Router 路由
this.route('oauthLink', {
path: '/oauthlink',
action: function() {
OAuth.callback('facebook', function(err, result) {
Meteor.call('fblogin', result, function(error, result) {
Meteor.loginWithToken(result.token, function(err) {
if(err) {
Meteor._debug("Error logging in with token: " + err);
}
})
});
});
}
});
或者没有 oauth.io
this.route('oauthLink', {
path: '/oauthlink',
action: function() {
var str = window.location.hash;
str = str.split('&');
var accessToken = str[0];
var expiresIn = str[1];
accessToken = accessToken.split('=');
expiresIn = expiresIn.split('=');
var result = {
access_token : accessToken[1],
expires_in : expiresIn[1]
};
Meteor.call('fblogin', result, function(error, result) {
console.log(result)
Meteor.loginWithToken(result.token, function(err) {
if(err) {
Meteor._debug("Error logging in with token: " + err);
}
})
});
}
});
不确定“操作”是否是正确的功能(我是 Iron-router 的新手),但它可以工作。
然后在服务器上
Meteor.methods({
fblogin: function(response) {
var identity = Meteor.call('$getIdentity', response.access_token);
// synchronous call to get the user info from Facebook
var serviceData = {
accessToken: response.access_token,
expiresAt: (+new Date) + (1000 * response.expires_in)
};
// include all fields from facebook
// http://developers.facebook.com/docs/reference/login/public-profile-and-friend-list/
var whitelisted = ['id', 'email', 'name', 'first_name',
'last_name', 'link', 'username', 'gender', 'locale', 'age_range'];
var fields = _.pick(identity, whitelisted);
_.extend(serviceData, fields);
var stuff = {
serviceName : 'facebook',
serviceData: serviceData,
options: {profile: {name: identity.name}}
};
var userData = Accounts.updateOrCreateUserFromExternalService(stuff.serviceName, stuff.serviceData, stuff.options);
var x = DDP._CurrentInvocation.get();
var token = Accounts._generateStampedLoginToken();
Accounts._insertLoginToken(userData.userId, token);
Accounts._setLoginToken(userData.userId, x.connection, Accounts._hashLoginToken(token.token))
x.setUserId(userData.userId)
return {
id: userData.userId,
token: token.token,
tokenExpires: Accounts._tokenExpiration(token.when)
};
},
$getIdentity: function(accessToken) {
try {
return HTTP.get("https://graph.facebook.com/me", {
params: {access_token: accessToken}}).data;
} catch (err) {
throw _.extend(new Error("Failed to fetch identity from Facebook. " + err.message),
{response: err.response});
}
}
});
几乎所有的 fblogin() 实际上都来自 Meteor 自己的 accounts-facebook 包。我只是修改它以满足我的需要。$getIdentity 是那里的逐字副本。
var stuff 包含 Facebook 数据(名称、访问令牌等)和流星帐户数据,并将其放入 Accounts.updateorcreateuserfromexternalservice,它会构建您的流星帐户 fblogin() 返回 userData,它从 Accounts.updateorcreate.. .. 并从中获得令牌,用于通过 Metoer.loginWithToken 登录。
如果我使用accounts-facebook,所有这一切都不会像我使用accounts-facebook那样打开一个新窗口或标签。从而解决了我遇到的主要问题,并且作为额外的奖励,它似乎在功能上等同于使用accounts-facebook。不再检查用户是否存在,如果存在,则使用“生成的密码”登录,或者如果它们不存在,则创建它们然后使用“生成的密码”登录
当然,这可以扩展到其他 oauth api,您显然不需要 oauth.io。我只是懒惰。希望其他人觉得这很有用。