2

Suppose I logged into my device's Facebook authentication, like system Facebook on iOS. I obtain an access token.

How can I use the access token to login to Meteor's Facebook Oauth provider?

4

4 回答 4

8

要使用通过其他方式(如 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包。您应该使用 Facebook 节点 API调用meteor add meteorhacks:npm并拥有一个文件: .package.json{ "fb": "0.7.0" }

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

在客户端上,使用适当的参数调用该方法,然后您就登录了!

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

于 2013-10-14T21:33:24.463 回答
1

基于 DrPangloss 上面最出色的答案,将其与这篇很棒的帖子相结合: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
      }
    });
  }
);
于 2014-06-21T17:59:58.203 回答
1

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

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

于 2013-08-08T10:34:15.843 回答
0

这个答案可以进一步改进,因为我们现在可以使用期货直接从 REST http 请求中调试令牌。必要的主要步骤仍然归功于@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 库。遵循他建议的相同原则,但这避免了集成额外库的需要

于 2016-12-14T21:46:45.870 回答