如何使用Facebook PHP SDK 3.0正确处理会话和访问令牌


How to properly handle session and access token with Facebook PHP SDK 3.0?

在 PHP 3.0 SDK 中,没有可用的 Facebook API 之外的getSession()或任何会话处理。几天前,Facebook的开发人员也以某种方式更新了JavaScript SDK,根据这个博客条目这个错误报告

在过去的几天里,发生了变化 引入到托管的 JS SDK 中 这打破了它之间的所有兼容性 以及当前的 PHP SDK(2.x 和 3.x(。 同时使用 JS 和 他们网站上的 PHP SDK 很可能 以查看服务器端 API 故障。

但是,我不知道这是否真的会影响我的问题。就像在这个问题的答案中一样,我正在使用 PHP 检索 OAuth 对话框的访问令牌,并将新的访问令牌保存在会话中。

当前解决方法

以下代码演示了我如何处理此会话。 $_REQUEST['session']是 OAuth 对话框响应的内容。

if(isset($_REQUEST['session'])) {
    $response = json_decode(stripslashes($_REQUEST['session']), true);
    if(isset($response['access_token'])) {
        $this->api->setAccessToken($response['access_token']);
        $_SESSION['access_token'] = $this->api->getAccessToken();
    }
}
elseif(isset($_SESSION['access_token']) && ! isset($_REQUEST['signed_request'])) 
    $this->api->setAccessToken($_SESSION['access_token']);
elseif(isset($_REQUEST['signed_request'])) {
    Session::invalidate('fbuser');
    $_SESSION['access_token'] = '';
}

以下是我处理用户数据的方式:

try {
    $this->user = Session::getVar('fbuser');
    if ($this->user === false || is_null($this->user)) {
        $facebookUser = $this->api->api('me?fields=id,name,first_name,last_name');
        $this->user = new FBUserModel(array('fbId' => $facebookUser['fbId'], ...));
        Session::setVar('fbuser', $this->user);
    }
}

问题所在

测试时一切看起来都很好。仅发生错误一次:设置权限后的第一次。现在,由于该应用程序处于联机状态,因此似乎平均每两个用户就会发生错误

$facebookUser = $this->api->api('me?fields=id,name,first_name,last_name');

出现错误:

An active access token must be used to query information about the current user.

问题

那么为什么会这样呢?调试非常困难,因为错误似乎仅在用户首次进入应用时发生,在应用身份验证和访问令牌更改后。甚至这种情况也不是每次都发生。我应该如何使用新的 PHP SDK 处理会话和访问令牌?

任何帮助将不胜感激!

编辑

我发现iFrame中的cookie/会话存在一些IE问题。如这篇博文所示。有了这个提示和一些进一步的研究,我在引导程序中添加了以下行:

ini_set('session.use_trans_sid', 1);
header('P3P:CP="IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT"');

现在它好多了,但是来自 50 个用户中大约 2 个的信息在步骤登录页面(身份验证(->公式 -> 和注册之间丢失。所以我仍然错过了一些东西。

编辑 2

我编辑了我的用户处理

if ($this->user === false || is_null($this->user)) {
    // get user data
}

if ((is_object($this->user) && $this->user->fbId == '') || $this->user === false || is_null($this->user)) {
    // get user data
}

这似乎有点帮助。我认为主要问题出在我的会议中的某个地方。

此外,我添加了一个try/catch块,以查看我的应用程序中的某个地方是否抛出了Facebook OAuthException。如果是这种情况,我会将顶部位置重定向到 Facebook 页面和选项卡以获取新的签名请求。虽然这可能有助于解决此问题,但我希望防止我的应用程序必须重定向用户。

编辑 3

经过几天的紧张调试和日志记录,我发现来自FB.ui permissions.request方法$_REQUEST['session']很少为空。

以下是我的处理方式:

这是我总是包含的内容:

FB.provide("UIServer.Methods", {'permissions.request': {size : {width: 575, height: 300}, url: 'connect/uiserver.php', transform : FB.UIServer.genericTransform}});

并且此函数在表单提交时调用。一直对我有用,但不知何故,尽管session == '',它仍然发送表格.

function getPermission(form) {
    session = $('#' + $(form).attr('id') + ' input[name="session"]');
    if($(session).val() != '') {
        form.submit();
        return;
    }
    FB.ui({method: "permissions.request", "perms": 'user_photos'}, function callback(info){
        if(info.status=='connected' && info.session !== null) {
            $(session).val(JSON.stringify(info.session));
            form.submit();
        }
    });
    return;
}
我现在

正在使用 PHP SDK 3.x,没有任何问题。

Naitik 类作者删除了 getSession(( 函数,现在如果你想知道用户是否经过身份验证,请使用 getUser((。

对于访问令牌,非常简单,使用此函数 getAccessToken((,您将获得访问令牌以进行 Graph 或 Rest API 调用。

$user = $facebook->getUser();
if ($user) {
//USER Logged-In
}
else {
//USER not Logged-In
}
//TO GET ACCESS TOKEN
$access_token = $facebook->getAccessToken();

//MAKE AN API CALL WITH IT
$user_info = $facebook->api('me?fields=id,name,first_name,last_name&access_token='.$access_token);

我的解决方案

好吧,由于在新的 JS SDK 发布之前,我所做的一切都只是一种解决方法,因此似乎没有最佳实践。将session.use_trans_sid设置为 1 并添加 P3P 标头有助于克服 IE iFrame cookie 问题(请参阅我的第一次编辑(。经过几天的繁重调试,我发现FB.ui的permission_request不会每次发送新的访问令牌(<5%(。

如果发生这种情况,则出了点问题。但是这个小东西让我发疯了。由于这种情况很少发生,我可以忍受将用户重定向回 facebook 选项卡以获取新的签名请求。使用新的 JS SDK,希望这种情况不会再发生。

更新:最终解决方案

我监督了一件小事,解决方案可以在这里找到:FB未定义问题
我没有异步加载 JS SDK!这解释了一切。有时 all.js 文件的加载速度不够快,因此会出现 JS 错误。因此,权限对话框和 JS 验证都不起作用,并且发送了一个空的 #session 输入值。

对于初学者,我会再调试一点。记录请求的内容。存储在 _SESSION 美元中的内容,以 _REQUEST 美元传递的内容。另外,检查这是否是浏览器问题(无论浏览器如何都会发生,还是有模式?

但是由于修复IE(P3P标头(中的cookie问题有所帮助,我的猜测是还剩下一些浏览器,拒绝第三方cookie。据我所知,某些版本的Safari和Opera默认这样做。此外,此错误指出没有提供access_token,而不是无效或过期的。

您可以通过禁用第三方 Cookie(例如在 Firefox 中使用 about:config(、取消对您的应用程序的授权(使用 Facebook 隐私设置底部的"应用程序和网站"部分(、删除 Cookie(与您的画布 URL 相关(然后启动应用程序来测试这一点。

顺便说一句,Facebook总是有可能不返回访问令牌,即使它应该返回,如错误17236中所述

嗨,

我遇到了同样的麻烦,似乎我已经通过观看 JS API 解决了它,并在用户信息可读的情况下重定向到 PHP-SDK 登录页面

例:

<script language="JavaScript">
function check_fb_status(){
    FB.api('/me', function(response){
     if(response.name) window.location='<?php echo $facebook->getLoginUrl(); ?>';
     else check_fb_status();
    });
}
check_fb_status();
</script>

如果脚本成功,它会加载登录页面,并且用户被 JS 和 PHP SDK 识别;)

供参考,Facebook在大约2小时前发布了对PHP SDK的更新,如果您使用JavaScript SDK在客户端上创建会话,则增加了对新cookie格式的支持。该更新可以在Facebook PHP-SDK GitHub存储库中找到。