如何使用本机设备Facebook登录Meteor



假设我登录了设备的Facebook身份验证,就像iOS上的系统Facebook一样。我获得了access token

如何使用access token登录Meteor的Facebook Oauth提供商?

要使用通过其他方式(如iOS Facebook SDK)获得的访问令牌登录Facebook,请在服务器上定义一个调用适当Accounts方法的方法:

$FB = function () {
    if (Meteor.isClient) {
        throw new Meteor.Error(500, "Cannot run on client.");
    }
    var args = Array.prototype.slice.call(arguments);
    if (args.length === 0) {
        return;
    }
    var path = args[0];
    var i = 1;
    // Concatenate strings together in args
    while (_.isString(args[i])) {
        path = path + "/" + args[i];
        i++;
    }
    if (_.isUndefined(path)) {
        throw new Meteor.Error(500, 'No Facebook API path provided.');
    }
    var FB = Meteor.npmRequire('fb');
    var fbResponse = Meteor.sync(function (done) {
        FB.napi.apply(FB, [path].concat(args.splice(i)).concat([done]));
    });
    if (fbResponse.error !== null) {
        console.error(fbResponse.error.stack);
        throw new Meteor.Error(500, "Facebook API error.", {error: fbResponse.error, request: args});
    }
    return fbResponse.result;
};
Meteor.methods({
    /**
     * Login to Meteor with a Facebook access token
     * @param accessToken Your Facebook access token
     * @returns {*}
     */
    facebookLoginWithAccessToken: function (accessToken) {
        check(accessToken, String);
        var serviceData = {
            accessToken: accessToken
        };
        // Confirm that your accessToken is you
        try {
            var tokenInfo = $FB('debug_token', {
                input_token: accessToken,
                access_token: Meteor.settings.facebook.appId + '|' + Meteor.settings.facebook.secret
            });
        } catch (e) {
            throw new Meteor.Error(500, 'Facebook login failed. An API error occurred.');
        }
        if (!tokenInfo.data.is_valid) {
            throw new Meteor.Error(503, 'This access token is not valid.');
        }
        if (tokenInfo.data.app_id !== Meteor.settings.facebook.appId) {
            throw new Meteor.Error(503, 'This token is not for this app.');
        }
        // Force the user id to be the access token's user id
        serviceData.id = tokenInfo.data.user_id;
        // Returns a token you can use to login
        var loginResult = Accounts.updateOrCreateUserFromExternalService('facebook', serviceData, {});
        // Login the user
        this.setUserId(loginResult.userId);
        // Return the token and the user id
        return loginResult;
    }
}

此代码取决于meteorhacks:npm软件包。您应该调用meteor add meteorhacks:npm,并使用Facebook节点API创建一个package.json文件:{ "fb": "0.7.0" }

如果使用demeteorizer部署应用程序,则必须编辑输出package.json,并将scrumptious依赖项从"0.0.1"设置为"0.0.0"

在客户端上,使用适当的参数调用方法,就可以登录了!

在Meteor 0.8+中,Accounts.updateOrCreateUserFromExternalService的结果已更改为包含{userId: ...}的对象,并且不再具有标记的令牌。

您可以在Meteor.user().services.facebook.accessToken获取Meteor.user()数据中的accessToken(请注意,这只能在服务器端访问,因为services字段没有暴露给客户端。

因此,当用户在你的流星网站上登录facebook时,这些字段将填充用户的facebook数据。如果你用mongo或其他gui工具检查你的流星用户数据库,你可以看到你可以访问的所有字段

在Pangloss博士上面最出色的回答的基础上,结合这篇精彩的帖子:http://meteorhacks.com/extending-meteor-accounts.html

在使用ObjectiveDDP试图让客户端保持登录时,您会遇到一些问题。包括标题:

#import "MeteorClient+Private.h"

并手动设置所需的内部构件。很快我会做一个陨石包和MyMeteor的扩展(https://github.com/premosystems/MyMeteor)但目前它是手动的。

loginRequest: {"accessToken":"XXXXXb3Qh6sBADEKeEkzWL2ItDon4bMl5B8WLHZCb3qfL11NR4HKo4TXZAgfXcySav5Y8mavDqZAhZCZCnDDzVbdNmaBAlVZAGENayvuyStkTYHQ554fLadKNz32Dym4wbILisPNLZBjDyZAlfSSgksZCsQFxGPlovaiOjrAFXwBYGFFZAMypT9D4qcZC6kdGH2Xb9V1yHm4h6ugXXXXXX","fbData":{"link":"https://www.facebook.com/app_scoped_user_id/10152179306019999/","id":"10152179306019999","first_name":"users' first name","name":"user's Full Name","gender":"male","last_name":"user's last name","email":"users@email.com","locale":"en_US","timezone":-5,"updated_time":"2014-01-11T23:41:29+0000","verified":true}}
Meteor.startup(
  function(){
    Accounts.registerLoginHandler(function(loginRequest) {
      //there are multiple login handlers in meteor.
      //a login request go through all these handlers to find it's login hander
      //so in our login handler, we only consider login requests which has admin field
      console.log('loginRequest: ' + JSON.stringify(loginRequest));
      if(loginRequest.fbData == undefined) {
        return undefined;
      }
      //our authentication logic :)
      if(loginRequest.accessToken == undefined) {
        return null;
      } else {
        // TODO: Verfiy that the token from facebook is valid...
        // https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow/v2.0#checktoken
        // graph.facebook.com/debug_token? input_token={token-to-inspect}&access_token={app-token-or-admin-token}
      }
      //we create a user if not exists, and get the userId
      var email = loginRequest.fbData.email || "-" + id + "@facebook.com";
      var serviceData = {
        id: loginRequest.fbData.id,
        accessToken: loginRequest.accessToken,
        email: email
      };
      var options = {
        profile: {
          name: loginRequest.fbData.name
        }
      };
      var user = Accounts.updateOrCreateUserFromExternalService('facebook', serviceData, options);
      console.log('Logged in from facebook: ' + user.userId);
      //send loggedin user's user id
      return {
        userId: user.userId
      }
    });
  }
);

这个答案可以进一步改进,因为我们现在可以使用futures直接调试RESThttp请求中的令牌。对于必要的主要步骤,@DoctorPangloss仍然功不可没。

//Roughly like this - I removed it from a try/catch
        var future = new Future();
        var serviceData = {
              accessToken: accessToken,
              email: email
            };
            var input = Meteor.settings.private.facebook.id + '|' + Meteor.settings.private.facebook.secret
            var url = "https://graph.facebook.com/debug_token?input_token=" + accessToken + "&access_token=" + input
            HTTP.call( 'GET', url, function( error, response ) {
                      if (error) {
                          future.throw(new Meteor.Error(503, 'A error validating your login has occured.'));
                      }
                      var info = response.data.data
                      if (!info.is_valid) {
                          future.throw(new Meteor.Error(503, 'This access token is not valid.'));
                      }
                      if (info.app_id !== Meteor.settings.private.facebook.id) {
                          future.throw(new Meteor.Error(503, 'This token is not for this app.'));
                      }
                      // Force the user id to be the access token's user id
                      serviceData.id = info.user_id;
                      // Returns a token you can use to login
                      var user = Accounts.updateOrCreateUserFromExternalService('facebook', serviceData, {});
                      if(!user.userId){
                        future.throw(new Meteor.Error(500, "Failed to create user"));
                      }
                      //Add email & user details if necessary 
                      Meteor.users.update(user.userId, { $set : { fname : fname, lname : lname }})
                      Accounts.addEmail(user.userId, email)
                      //Generate your own access token!
                      var token = Accounts._generateStampedLoginToken()
                      Accounts._insertLoginToken(user.userId, token);
                      // Return the token and the user id
                      future.return({
                        'x-user-id' : user.userId,
                        'x-auth-token' : token.token
                      })
            });
          return future.wait();

使用这个来代替@DoctorPangloss建议的JS库。遵循他建议的相同原则,但这避免了集成额外库

的需要

最新更新