4

我正在开发一个小型个人项目,用户可以通过内置的 Meteor.js 使用 Facebook 登录{{loginButtons}} 但问题是,当通过全屏运行应用程序时,apple-mobile-web-app-capable没有弹出对话框请求许可。屏幕只是一片空白。

我根本没有使用 facebook 的 sdk。

它在移动 Safari 中运行良好。我已经将它部署到流星进行一些最终测试,所以它不是本地主机问题。

这是否可能无需创建我自己的用户创建和/或服务器端实现和/或 facebook 的 sdk?最终我计划添加更多,比如 twitter 和 google。

另外,我还在使用 iOS 6.1

4

3 回答 3

3

更新,请参阅我的其他答案以获取更多改进的示例

所以我只花了大约一个小时弄清楚一些东西。我认为最好的办法是放弃 Meteor 的内置帐户系统 相反,我使用“oauth.io”(无从属关系)和“流星路由器”,我将使用 Meteor 的 Accounts.createUser() 创建用户;最好的部分是它适用于 localhost 和我的 iPhone,所以我不必继续部署它来测试。

Meteor.startup(function () {
    OAuth.initialize('my key');
});

我的路线:

Meteor.Router.add({
    '/oauth': function() {
      console.log('oauthed');
        OAuth.callback('facebook', function(err, result) {
            var token = result.access_token;
            var url = 'https://graph.facebook.com/me?access_token='+token;

            $.get( url, function( data ) {
                alert(data.email)
                console.log(data);
            });
        });
    }
});

然后是一个简单的锚

$('#loginfb').live('click', function() {
    OAuth.redirect('facebook', "/oauth");
});

据我所知,但它适用于apple-mobile-web-app-capable 我能够验证并获取我的 Facebook 信息。它的工作比我想做的要多,但不是太难。

所以我正在考虑用这种方法获取用户的电子邮件,然后使用:

Accounts.createUser({
    email: data.email, 
    password: data.id //since your Facebook id can't change
});

这样用户可以稍后更改或重置它,或者我可以提示他们更改它。

然后我要检查该用户是否存在,(不知道如何做到这一点)如果他们存在,那么做:

Meteor.loginWithPassword(data.email, data.id);

好的。所以我稍微调整了我的设置。

我不得不切换到主干路由器,由于某种原因,Meteor Router 每次加载 /oauth 时都会刷新页面两次。骨干没有。

我添加了一个用于生成密码的服务器端功能。

Meteor.startup(function () {
  Backbone.history.start({
      pushState: true,
      root: "/"
  });

  OAuth.initialize('key goes here');
});

var $Router = Backbone.Router.extend({
  routes: {
    "/": "home",
    "oauth": "oauth",
    "": "home"
  },
  home: function () {
    console.log('home')
  },
  oauth: function () {
    OAuth.callback('facebook', function (err, result) {
      console.log(result);
      var token = result.access_token;
      var url = 'https://graph.facebook.com/me?access_token=' + token;
      $.get(url, function (data) {
        var email = data.email;
        var pass = Meteor.call('generatePass', data, function (error, result) {
          Meteor.loginWithPassword(email, result, function (error) {
            if (error) {
              var options = {};
              options.email = email;
              options.password = pass;
              Accounts.createUser(options, function (error) {
                if (error) {
                  console.log(error);
                  $router.navigate('/');
                } else {
                  //Account creation successful return to index
                  $router.navigate('/');
                }
              })
            } else {
              //Login successful return to index
              $router.navigate('/');
            }
          });
        });
      });
      return false;
    });
  }
});

var $router = new $Router();
// I use jquery for events, I don't like to use meteor's template event handlers.

$('#loginfb').click(function (event) {
  event.preventDefault();
  //have to use redirect, otherwise popup won't work correctly since we're using mobile-webapp-capable
  OAuth.redirect('facebook', "/oauth");
});


//server.js
Meteor.methods({
  generatePass: function (data) {
    // .. do stuff ..
    var pass = fancy function that creates a password based on the supplied data;
    return pass;
  }
});

到目前为止,它只适用于 Facebook,并且没有经过很好的测试。我喜欢一些指导和/或建设性的批评。

于 2013-11-07T02:48:31.303 回答
1

我想出了一个更好的方法来做到这一点,而不使用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。我只是懒惰。希望其他人觉得这很有用。

于 2014-01-14T02:36:57.997 回答
1

问题似乎是 oauth 包使用 window.open 打开一个弹出窗口。我之前没有使用过 apple-mobile-web-app-capable 的经验,但一些研究似乎表明 window.open 不适用于它。该解决方案似乎正在测试客户端是否正在使用可以使用的全屏应用程序

window.navigator.standalone

根据https://developer.apple.com/library/safari/documentation/AppleApplications/Reference/SafariHTMLRef/Articles/MetaTags.html

不幸的是,假设弹出窗口已打开,oauth 登录工作流程有点尴尬。我不确定进行此测试的最佳位置在哪里,以及用户在新窗口中输入其用户名/密码后是否会尝试登录或创建用户。

我尝试在accounts-oauth-helper/oauth_client.js 中将window.open 方法更改为window.location,然后它确实打开了窗口,但我的redirect_uri 出现问题,可能是因为我是通过手机在本地主机项目上执行此操作的所以我不确定登录过程是否会在登录发生后继续。

在使用 apple-mobile-web-app-capable 时,这似乎会影响所有登录提供程序,因此这可能是一个需要修复的错误。稍后我将尝试设置一个项目以更好地了解这一点,并让您知道它是如何进行的。

于 2013-11-06T04:14:26.943 回答