Facebook JS SDK和PHP SDK访问令牌冲突

3

我已经在StackOverflow上搜索并向Facebook提交了一个错误报告,但都没有得到帮助。我花费了超过40个小时才找到问题所在。我认为这是FB.INIT和PHP访问令牌之间的冲突,当服务器有重度.htaccess Mod Rewrites以改变URL为有效查询字符串时。我已将其编写为错误报告,但Facebook认为这是用户问题。我甚至使用了他们回答中的代码,但仍然存在错误。

以下是原始问题。 在我的测试站点上,我可以很好地使用PHP SDK和JS SDK。两者都允许登录并相互通信。在浏览页面或执行即将更新客户端的所有功能时,没有任何问题。

现在我正在尝试在具有重度.htaccess mod Rewrites的客户网站中安装新的OAuth更新。我的测试网站没有Mod ReWrites。

起初,您可以使用PHP轻松登录。但是一旦您转到站点内的另一个页面,您就会失去访问令牌,并出现常见的错误:必须使用活动访问令牌来查询有关当前用户的信息。

通过检查PHP api是否失败,然后使用从Facebook的授权页面(针对:https://graph.facebook.com/oauth/access_token)获取的file_get_contents命令并重置访问令牌来解决此问题。这起作用了。但是,这会导致FB.init失败,并出现响应错误:必须使用活动访问令牌来查询有关当前用户的信息。由FB.api('/me')回调。

因此,为了解决这个问题,我不得不将PHP的访问令牌传递到SESSION中,并在我的api调用中放置它。就像这样,FB.api('/me/?access_token=')。这起作用了。因此,我的网站通过主导PHP与JS作为辅助实现与Facebook的通信。

目前的问题是:如果用户来到网站并未登录标准PHP Facebook函数并使用使用FB JS SD的函数,则网站会提示JS登录,并获得该网站功能所需的适当权限。用户接受并登录。从JS方面来看,一切都很好。控制台日志转储告诉我这一点。

问题是:PHP不会承认JS SDK设置的cookie中的Access_token,也不会从file_get_contents接收cookie(返回失败的HTTP请求400)。因此,尽管用户通过JS登录,但PHP仍然不接受其登录,并显示PHP getLoginUrl函数。

当在PHP facebook对象上执行var_dump时,我们看到所有字段都包含数据;代码,状态,访问令牌,算法等。但是,当在每个页面上执行$facebook->api('/me')(上面是成功的)时,我们会收到错误:必须使用活动访问令牌来查询有关当前用户的信息。

我的结论是:基于 JS 感知的 URL 生成代码与 PHP 的实际 URL 不匹配。虽然可以很容易地将 JS 强制转换为 PHP 访问令牌,但无法让 PHP 受 JS 控制。
以下是每个页面上的 PHP 代码。
$app_id = 'APP_ID';
$app_secret = 'APP_SEC';
$my_url = 'http://'.$_SERVER['HTTP_HOST'];
$facebook = new Facebook(array(
  'appId'  => $app_id,
  'secret' => $app_secret,
));
$_SESSION[fbappID] = $facebook->getAppId();
$_SESSION[fbaccTok] = $facebook->getAccessToken();
$sigReq = $facebook->getSignedRequest();
$code = $sigReq[code];
$userID = $facebook->getUser();
if($userID)
{
  try {
    $user_profile = $facebook->api('/me');
  } catch (FacebookApiException $e) {
    error_log($e);
    $token_url = "https://graph.facebook.com/oauth/access_token?"
       . "client_id=" . $app_id . "&redirect_uri=" . urlencode($my_url)
       . "&client_secret=" . $app_secret . "&code=" . $code;
    $response = file_get_contents($token_url);
    $params = null;
        parse_str($response, $params);
        if($params[access_token]!="")
    {
      $facebook->setAccessToken($params[access_token]);
      $_SESSION[fbaccTok] = $facebook->getAccessToken();
    }
    try{
      $user_profile = $facebook->api('/me');
    }catch(FacebookApiException $e) {
      error_log($e);
      $userID = null;
    }
  }
}
if($userID)
{
  $user_profile = $facebook->api('/me');
  $logout =  $facebook->getLogoutUrl();
}
else
{
  $login = "<a href='".$facebook->getLoginUrl()."'>Log In with Facebook</a>";
}

使用的Javascript:

<script>
 FB.init({
  appId  : '$_SESSION[fbappID]',
status : true,
  cookie : true, 
  xfbml  : true,  
  oauth : true 
  });
  FB.api('me/permissions/?access_token=<?php print $_SESSION[fbaccTok]?
  >',function(response){console.log(response)});
</script>

答案:

这里是答案:为了允许Javascript成为主要的入口点,您必须选择PHP或Javascript并使它们成为主导,以强制使用另一个的访问令牌。以下是Javascript代码:

window.fbAsyncInit = function() {

  FB.init({
      appId  : '12345',
      channelURL : '/channel.php',
      status : true,
      cookie : true, // enable cookies to allow the server to access the session
      xfbml  : true,  // parse XFBML
      oauth : true //enables OAuth 2.0
    });
 FB.getLoginStatus(function(response){
    if(response.authResponse){
        FB.accessToken = ;
        createCookie('fbToken',response.authResponse.accessToken,.1);
        createCookie('fbID',response.authResponse.userID,.1);
    }
     });
 FB.Event.subscribe('auth.login', function(response) {
    createCookie('fbToken',response.authResponse.accessToken,.1);
    createCookie('fbID',response.authResponse.userID,.1);
    createCookie('fbLogin',1,30);
    window.location.reload();

 });
 FB.Event.subscribe('auth.logout', function() {
        eraseCookie('fbLogin');
         eraseCookie('fbToken');
         eraseCookie('evFB.uid');
 });
}

createCookie和eraseCookie是可在网络上找到的cookie函数。这里提供的是大概的代码,不是细致精炼的版本。基本上,我自己创建了Cookies以传递信息。由于FB JS SDK在登录和注销时刷新页面,因此我可以在PHP接管页面刷新之前删除、创建或修改Cookies。

现在看一下强制JS cookie访问令牌的PHP代码。

require_once("/facebook.php");

$facebook = new Facebook(array(
  'appId'  => $app_id,
  'secret' => $app_secret,
));
$my_url = $facebook->returnGetUrl();
$_SESSION[fbaccTok] = (isset($_COOKIE[fbToken]))?$_COOKIE[fbToken]:$facebook->getAccessToken();


$sigReq = $facebook->getSignedRequest();
$code = ($_REQUEST[code]=='')?$sigReq[code]:$_REQUEST[code];

$GLOBALS[fbUser]= $facebook->getUser();

if(isset($_COOKIE[fbLogin]))
{
    if($_COOKIE[fbLogin]==1)
    {
        $GLOBALS[fbUser] = $facebook->getUser();
        //print $GLOBALS[fbUser];
    }
    else
    {
        $GLOBALS[fbUser] = null;
    }
}
else
{
    $GLOBALS[fbUser] = null;
}
if($GLOBALS[fbUser] && $_COOKIE[fbToken])
{
    $GLOBALS[fbArray] = array(
        'access_token' => $_COOKIE[fbToken]
        );
        try {
            $GLOBALS[fbUserProfile] = $facebook->api('/me','GET',$GLOBALS[fbArray]);
            //print_r($GLOBALS[fbUserProfile]);


        } catch (FacebookApiException $e) {
            error_log($e);

        }
}

希望这能帮到您。

这也是使用PHP 3.1.1 SDK的。 - V Rodg
这让我更好地理解如何处理!使用fb js sdk访问令牌通过JavaScript创建Cookie,然后在fb php sdk中检索它绝对有效。 - Patareco
1个回答

0
如果不使用Mod Rewrites可以正常工作,但使用Mod Rewrites无法正常工作,那么问题就出在这上面。
你可以创建另一个Facebook测试应用程序并将其托管在没有Mod Rewrites的单独服务器上,然后逐步添加每个Mod Rewrites,直到出现问题,以查看是哪一个导致了问题。

我遇到了同样的问题,而且我没有设置任何mod rewrite。 - Matrym
我已经更新了我的问题,包括答案。 - V Rodg
1
@V Rodg,你应该将它作为答案添加,而不是放在问题中,现在它仍然被标记为未回答。 - xorinzor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接