【问题标题】:Facebook PHP SDK session lost, needs JS SDK refreshFacebook PHP SDK 会话丢失,需要刷新 JS SDK
【发布时间】:2013-01-05 12:19:30
【问题描述】:

真的很奇怪,使用 PHP SDK (v 3.2.2) 时 Facebook 会话似乎丢失了 ($user = 0)。 JS SDK 需要重新加载我的页面以恢复 Facebook 会话。这个问题时有发生,有时 Facebook 会话丢失,有时它工作正常。

session_start();

// Run Facebook API
$facebook = new Facebook(array(
  'appId'  => $config['facebook']['id'],
  'secret' => $config['facebook']['secret']
));

// Fetch user
$user = $facebook->getUser();
if($user) {
  try {
    // Just to be sure, add access token to each request
    $user['access_token'] = $facebook->getAccessToken();    

    // Fetch user details
    $user = $facebook->api('/me?access_token='.$user['access_token']);          
  }
  catch (FacebookApiException $e) {
    error_log($e);
    $user = null;
  } 
}

主要问题是 $user = $facebook->getUser();返回 0。但是,当用户实际连接时,JS SDK 检测到 auth.login 事件并重新加载页面(另一件奇怪的事情,我使用 auth.login,因为 auth.authResponseChange 事件每秒都会被触发)。现在 $user = $facebook->getUser();返回用户的 uid。

window.fbAsyncInit = function() {
  FB.init({
    appId : appId,
    channelUrl : '//domain.com/signon/channel.php',
    status     : true,
    cookie     : true,
    xfbml      : true 
  });
  FB.Event.subscribe('auth.login', function(response) {
    location.reload();
  });
};

在 Facebook Developer 中,我定义了应用程序域 (domain.com) 和站点 URL (http://domain.com/)。已经尝试过带/不带斜杠的站点网址,但没有解决问题。

知道发生了什么,为什么 Facebook PHP SDK 没有立即检测到用户的会话/不断丢失用户的会话并需要重新加载?这个问题确实会导致糟糕的用户体验。

非常感谢!

罗宾

【问题讨论】:

    标签: php facebook facebook-graph-api facebook-php-sdk connect


    【解决方案1】:

    我最近遇到了同样的问题,似乎如果在 5 分钟左右不活动后重新加载,会话不会持续。有时有效,有时无效。

    上周我一直在研究它,我能想到的唯一解决方案是使用 JS SDK 进行页面重新加载:

    FB.Event.subscribe('auth.login', function(response) {
          window.location.reload();
        });
    

    但我同意,就用户体验而言,这不是一个非常优雅的解决方案。您应该在 PHP SDK 中传递 cookie 参数,在 JS SDK 中传递 oauth 参数,看看它是否有效(它不适合我):

    $facebook = new Facebook(array(
      'appId'  => $config['facebook']['id'],
      'secret' => $config['facebook']['secret'],
      'cookie' => true
    ));
    

    FB.init({
        appId : appId,
        channelUrl : '//domain.com/signon/channel.php',
        status     : true,
        cookie     : true,
        xfbml      : true,
        oauth      : true
      }); 
    

    更奇怪的是,我从 Github 重新下载了 latest PHP SDK 并将其上传到沙盒环境(Apache,PHP 5.4)。我按原样运行了示例(使用 JS SDK),它有同样的问题!

    现在,如果以上内容还不能解决问题,我还有一些建议。

    稍微改变 SDK

    首先,通过

    $facebook->getAccessToken();

    如果 $user 返回 0 对你没有好处。但是,在对 base_facebook.php 进行了一些挖掘之后,我注意到 getCode() 方法实际上使用 $_REQUEST 从查询中检索授权码参数。

    来自 PHP 手册,$_REQUEST 是

    默认情况下包含 $_GET、$_POST 和 $_COOKIE 内容的关联数组。

    但是

    它与 $_GET、$_POST 或 $_COOKIE 非常不同。

    这可能有点麻烦,具体取决于您的设置。因此,请在 base_facebook.php 中找到函数 getCode(),如下所示:

    protected function getCode() {
    if (isset($_REQUEST['code'])) {
        if ($this->state !== null &&
                isset($_REQUEST['state']) &&
                $this->state === $_REQUEST['state']) {
    
            // CSRF state has done its job, so clear it
            $this->state = null;
            $this->clearPersistentData('state');
            return $_REQUEST['code'];
        } else {
            self::errorLog('CSRF state token does not match one provided.');
            return false;
        }
    }
    
    return false;
    }
    

    并将查询合并到一个新的数组/变量中(我们称之为$code_array)以包含$_GET$_POST$_COOKIE 数组使用array_merge() 像这样:

    $code_array = array_merge($_GET,$_POST,$_COOKIE);
    

    最终得到的是一个数组,其中包含来自各个请求的所有数据。只需在函数内将$_REQUEST 替换为$code_array,即

    \\replace $_REQUEST with $code_array;
    if (isset($code_array['code'])) {
    if ($this->state !== null &&
            isset($code_array['state']) && 
            $this->state === $code_array['state']) { //...and so on for the rest
    

    这应该可以很好地完成工作(希望如此)。

    可选 - 延长您的访问令牌生命周期

    这是可选的,但我还是包含了它。大多数新应用程序已经拥有长期存在的访问令牌,但以防万一,您可以使用$facebook->setExtendedAccessToken(); 方法来转换您现有的访问令牌。

    注意:您必须先调用$facebook->setExtendedAccessToken();,然后才能使用getAccessToken() 方法实际获取访问令牌。

    现在,使用您的代码,您将拥有

    $user = $facebook->getUser();
      if($user) {
        try {
        // Just to be sure, add access token to each request
        $facebook->setExtendedAccessToken();
        $access_token = $facebook->getAccessToken();
        // Fetch user details
        $user = $facebook->api('/me?access_token='.$access_token);
        }
    //and so on..
    

    结论

    将 $_REQUEST 分解为 $_GET、$_POST 和 $_COOKIE(尽管默认情况下它包括所有三个)似乎确保我们可以轻松获取 SDK 设置的 cookie。我说似乎是因为见鬼,我自己也不是 100% 确定。

    我使用上述方法让它在我的情况下工作,所以我希望分享一些知识,因为我一直在这个问题上失去太多睡眠,并且找不到可行的解决方案。

    希望这会有所帮助!

    编辑:我忘了提,从

    更改 API 请求
    $user_profile = $facebook->api('/me');
    

    $user_profile = $facebook->api('/'.$user.'?access_token='.$access_token);
    

    我也做过这件事,并且有所作为。 :)

    【讨论】:

    • 致电$facebook->setExtendedAccessToken(); 为我工作,谢谢。
    • 我有一个应用程序,其站点位于根目录,iframe 小部件位于 /widgets。除了您在基本 facebook 中的更改之外,我还必须为 /widgets 中的 iframe 小部件创建一个新应用程序。现在根域上的会话似乎很好。
    • 我收回了,会话很好,但是页面空闲几分钟后用户仍然返回 0。
    • 你是如何实例化 facebook 类的?即当您调用 $facebook = new Facebook($config); 时,您的 $config 数组中有什么?
    • 另外,Facebook API 会话不是无限期的,它们最终会过期。我们正在开发一个使用 PHP-SDK 的 Web 应用程序,通常会话/令牌将在 5-10 分钟没有用户活动后过期,这是意料之中的。一些 API,如 Instagram API 有一个终身令牌,但 Facebook 是相当动态的。当您积极使用您的网站时,您的会话/令牌是否会过期?
    【解决方案2】:

    可能是因为 Facebook PHP SDK 不是 ajax,而且我们使用的是 PHP 页面,而且我们的服务器加载速度比 Facebook 的身份验证过程更快,以读取有效会话。 Facebook PHP SDK 需要的是从我们的应用程序刷新会话验证页面,这应该内置到 Facebook Javascript SDK 中,但看起来它不是。

    【讨论】:

      猜你喜欢
      • 2011-09-21
      • 2013-03-15
      • 1970-01-01
      • 1970-01-01
      • 2013-09-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-26
      相关资源
      最近更新 更多