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

IT技术 php javascript facebook session
2021-03-22 12:10:27

在 PHP 3.0 SDK 中,没有getSession()没有任何来自 Facebook api 外部的会话处理可用。根据此博客条目此错误报告,几天前 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 块来查看我的应用程序中是否有 FacebookOAuthException被抛出。如果是这种情况,我会将顶部位置重定向到 Facebook Page 和 Tab 以获取新的签名请求虽然这可能有助于解决这个问题,但我想防止我的应用程序必须重定向用户。


编辑 3

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

这是我的处理方式:

这是我一直包括的东西:

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;
}
5个回答

我现在使用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);
@Sergey Nester:我知道,但是这个项目和其他项目需要使用 JS 对话框。如果根本不可能将旧的 JS 与新的 PHP SDK 结合起来,我可以反驳。但正如已经提到的,我的解决方法是在 >95% 的情况下工作。只有一件小事让我远离 100%。我也可以捕获错误,重新加载整个页面并获取新的签名请求,但我想知道为什么会发生这种情况。
2021-05-05 12:10:27
你没有理解我的问题:我必须通过 JavaScript 获得许可。PHP 3.x SKD 与当前可用的 JS SDK 不能很好地通信。访问令牌不会自动更改。所以,我写了这个解决方法来在会话中保存新的访问令牌。并且这仅在 95% 的情况下有效……而不是 100%
2021-05-20 12:10:27
@Sascha Galley - 你真的需要只使用 JS 获得许可吗?使用 PHP SDK 获取许可应该可以避免这个问题。
2021-05-20 12:10:27

我的解决方案

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

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

更新:最终解决方案

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

很高兴你把事情解决了!希望 PHP-SDK 将很快得到更新,以便您正确集成您的系统。
2021-05-08 12:10:27

对于初学者,我会多调试一点。记录请求的内容。$_SESSION 中存储的内容,$_REQUEST 中传递的内容。另外,检查它是否是浏览器问题(是否与浏览器无关,或者是否存在模式?)

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

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

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

谢谢,这是迄今为止最好的答案。我不会立即接受它,让它开放供进一步研究,但我现在就给你应得的赏金。所以...请继续关注:)
2021-05-19 12:10:27

嗨,我遇到了同样的麻烦,似乎我已经通过观看 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 识别;)

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