使用 PHP SDK 访问 Facebook Graph API 的代码在重新加载页面时不起作用

Code to access Facebook Graph API with PHP SDK not working when reloading page

我正在编写一些代码来获取由 Facebook 用户管理的 Facebook 页面,使用 Facebook Graph API。我的代码请求用户的授权并获得一个令牌,使它能够获取此信息,然后将其存储在会话中。问题是,如果我重新加载页面,存储的令牌将被取消设置,我将无法获得由 Facebook 用户管理的 Facebook 页面。

当页面重新加载时,令牌显然已通过 'validateExpiration()' 函数撤销。

我错过了什么?

这是我的代码:

session_start();

// Load the Facebook PHP SDK
require_once __DIR__ . '/facebook-sdk-v5/autoload.php';

define('APP_ID', 'xxxxxxxxxxxxxxxx');
define('APP_SECRET', 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx');

$fb = new Facebook\Facebook([
    'app_id'     => APP_ID,
    'app_secret' => APP_SECRET,
    'default_graph_version' => 'v2.7'
]);

if(isset($_SESSION['fb_access_token'])) {

  echo '$_SESSION["fb_access_token"] = ' . $_SESSION['fb_access_token'] . '<br>';

// Create a new AccessToken object from its string code. Needed?
$accessToken = new Facebook\Authentication\AccessToken($_SESSION['fb_access_token']);

  $expirationDate = $accessToken->getExpiresAt();
  echo 'Token expires at: ' . var_dump($expirationDate) . '<br>'; // Returns null!

// verifies the validity and expiration of the token
$oAuth2Client = $fb->getOAuth2Client();
$tokenMetadata = $oAuth2Client->debugToken($accessToken);


try {
  echo 'Validating token<br>';
    $tokenMetadata->validateAppId(APP_ID);
    $tokenMetadata->validateExpiration(); // This apparently throws an exception

} catch(Facebook\Exceptions\FacebookSDKException $e) {
  echo 'I will now unset the token<br>';
    unset($accessToken);
    unset($_SESSION['fb_access_token']);
}

if(!isset($accessToken)){
  echo 'Token not set!';
  exit;
}

// Check permissions
if (isset($accessToken)) {
  $response = $fb->get('/me/permissions', $accessToken);

  $permissions = $response->getDecodedBody();
  echo 'Permissions: ';
  print_r($permissions);
  $permissions_list = [];

  foreach($permissions['data'] as $perm) {
      if($perm['status'] == 'granted') {
          $permissions_list[] = $perm['permission'];
      }
  }
  echo 'Permissions list: ';
  print_r($permissions_list);


  if(!in_array('pages_show_list', $permissions_list)) {

    echo 'I will now unset the token<br>';
    unset($accessToken);
    unset($_SESSION['fb_access_token']);
  }

}
} else {

$helper = $fb->getRedirectLoginHelper();

try {
    $accessToken = $helper->getAccessToken();
} catch(Facebook\Exceptions\FacebookResponseException $e) {
    echo 'Graph returned an error: ' . $e->getMessage();
    exit;
} catch(Facebook\Exceptions\FacebookSDKException $e) {
    echo 'Facebook SDK returned an error: ' . $e->getMessage();
    exit;
}
}

if(isset($accessToken)) {
// Logged in!

// Save the string code of the AccessToken to re-create it later
$_SESSION['fb_access_token'] = (string) $accessToken;

echo '$_SESSION["fb_access_token"] = ' . $_SESSION['fb_access_token'] . '<br>';

try {
    $response = $fb->get('/me/accounts', $accessToken);
    $data = $response->getDecodedBody();
    echo '<pre>';
    print_r($data);
    echo '</pre>';
    exit;

} catch(Facebook\Exceptions\FacebookResponseException $e) {
    echo 'Graph returned an error: ' . $e->getMessage();
    exit;
} catch(Facebook\Exceptions\FacebookSDKException $e) {
    echo 'Facebook SDK returned an error: ' . $e->getMessage();
    exit;
}
} else {
$helper = $fb->getRedirectLoginHelper();
$permissions = ['email', 'public_profile','pages_show_list']; // Optional permissions

$redirect_url = "https://www.example.com/this_file.php";
$loginUrl = $helper->getLoginUrl($redirect_url, $permissions);
echo '<a href="' . $loginUrl . '">Log in with Facebook!</a>';
}

我终于明白了!

问题在于 Facebook AccessToken 是一个具有两个属性的对象:一个字符串代码和一个具有到期时间的日期时间 PHP 对象 - 请参阅以下代码: Github repository of Facebook's PHP SDK。我第一次获得新令牌时,它的到期时间已设置,一切正常。但是当我将其代码存储在会话中并尝试使用

重新创建它时
$accessToken = new Facebook\Authentication\AccessToken($_SESSION['fb_access_token']);

我没有设置过期时间,对象默认为 UNIX 时间 0(即 1970 年 1 月 1 日)。因为在我调用函数 validateExpiration() 之后,这将 return 访问令牌已过期(它只查看 AccessToken 对象中的过期时间)并将触发异常。

解决方法:不要重新验证存储的令牌。 validateAppId(APP_ID) 继续有效。对于到期时间,要么存储它(例如在会话中)并在重新创建 AccessToken 对象时使用它,要么调用 Graph API。如果此调用 return 出错(可能是因为令牌已过期或用户撤销了权限),请通过 Facebook 登录向用户索取新令牌。