Facebook SDK вернул ошибку: проверка подделки на основе перекрестного запроса не удалась. Параметр «состояние» из URL-адреса и сеанса не соответствует

Я пытаюсь получить идентификатор пользователя Facebook, используя php sdk, как это

$fb = new Facebook\Facebook([ 'app_id' => '11111111111', 'app_secret' => '1111222211111112222', 'default_graph_version' => 'v2.4', ]); $helper = $fb->getRedirectLoginHelper(); $permissions = ['public_profile','email']; // Optional permissions $loginUrl = $helper->getLoginUrl('http://MyWebSite', $permissions); echo '<a href="' . $loginUrl . '">Log in with Facebook!</a>'; try { $accessToken = $helper->getAccessToken(); var_dump($accessToken); } catch (Facebook\Exceptions\FacebookResponseException $e) { // When Graph returns an error echo 'Graph returned an error: ' . $e->getMessage(); exit; } catch (Facebook\Exceptions\FacebookSDKException $e) { // When validation fails or other local issues echo 'Facebook SDK returned an error: ' . $e->getMessage(); exit; } if (!isset($accessToken)) { if ($helper->getError()) { header('HTTP/1.0 401 Unauthorized'); echo "Error: " . $helper->getError() . "\n"; echo "Error Code: " . $helper->getErrorCode() . "\n"; echo "Error Reason: " . $helper->getErrorReason() . "\n"; echo "Error Description: " . $helper->getErrorDescription() . "\n"; } else { header('HTTP/1.0 400 Bad Request'); echo 'Bad request'; } exit; } // Logged in echo '<h3>Access Token</h3>'; var_dump($accessToken->getValue()); // The OAuth 2.0 client handler helps us manage access tokens $oAuth2Client = $fb->getOAuth2Client(); // Get the access token metadata from /debug_token $tokenMetadata = $oAuth2Client->debugToken($accessToken); echo '<h3>Metadata</h3>'; var_dump($tokenMetadata); // Validation (these will throw FacebookSDKException's when they fail) $tokenMetadata->validateAppId($config['11111111111']); // If you know the user ID this access token belongs to, you can validate it here //$tokenMetadata->validateUserId('123'); $tokenMetadata->validateExpiration(); if (!$accessToken->isLongLived()) { // Exchanges a short-lived access token for a long-lived one try { $accessToken = $oAuth2Client->getLongLivedAccessToken($accessToken); } catch (Facebook\Exceptions\FacebookSDKException $e) { echo "<p>Error getting long-lived access token: " . $helper->getMessage() . "</p>\n\n"; exit; } echo '<h3>Long-lived</h3>'; var_dump($accessToken->getValue()); } $_SESSION['fb_access_token'] = (string)$accessToken; 

но он дает мне эту ошибку:

 Facebook SDK returned an error: Cross-site request forgery validation failed. The "state" param from the URL and session do not match. 

пожалуйста, любая помощь. Я новичок в php и Facebook sdk. Спасибо за любую помощь заранее.

Я обнаружил, что до тех пор, пока я разрешал сеансы PHP до создания URL-адреса входа, а в верхней части скрипта Facebook в конечном итоге перенаправляется, он отлично работает сам по себе, не устанавливая cookie ( в соответствии с ответом ale500 ). Это использует 5.1-разрядную версию sdk.

В верхней части обоих сценариев я добавил …

 if(!session_id()) { session_start(); } 

… и это «просто сработало».

Вот полный пример, который работает для меня:

auth.php

 if (!session_id()) { session_start(); } $oFB = new Facebook\Facebook([ 'app_id' => FACEBOOK_APP_ID, 'app_secret' => FACEBOOK_APP_SECRET ]); $oHelper = self::$oFB->getRedirectLoginHelper(); $sURL = $oHelper->getLoginUrl(FACEBOOK_AUTH_CALLBACK, FACEBOOK_PERMISSIONS); // Redirect or show link to user. 

auth_callback.php

 if (!session_id()) { session_start(); } $oFB = new Facebook\Facebook([ 'app_id' => FACEBOOK_APP_ID, 'app_secret' => FACEBOOK_APP_SECRET ]); $oHelper = self::$oFB->getRedirectLoginHelper(); $oAccessToken = $oHelper->getAccessToken(); if ($oAccessToken !== null) { $oResponse = self::$oFB->get('/me?fields=id,name,email', $oAccessToken); print_r($oResponse->getGraphUser()); } 

Зачем?

В качестве дополнительной заметки это объясняется в Документах по репо. Посмотрите предупреждение на этой странице .

Предупреждение: FacebookRedirectLoginHelper использует сеансы для хранения значения CSRF. Перед вызовом метода getLoginUrl () вы должны убедиться, что у вас есть сеансы. Обычно это делается автоматически в большинстве веб-фреймворков, но если вы не используете веб-инфраструктуру, вы можете добавить session_start (); в верхней части скриптов login.php и login-callback.php. Вы можете перезаписать обработку сеанса по умолчанию – см. Ниже пункты расширения.

Я добавляю эту заметку, потому что важно иметь в виду, если вы выполняете собственное управление сеансом или параллельно используете несколько веб-серверов. В таких случаях использование методов сеанса php по умолчанию не всегда будет работать.

вставьте этот код после $ helper = $ fb-> getRedirectLoginHelper ();

  $_SESSION['FBRLH_state']=$_GET['state']; 

и он будет работать или для более подробной информации посетите приложения для входа в facebook

Здесь уже много замечательных ответов, вот что помогло мне,

Я обнаружил, что проблема связана с ошибкой подписи на основе перекрестного запроса. Требуемое «состояние состояния» отсутствует в коде FB, и вот решение

После этой строки

 $helper = $fb->getRedirectLoginHelper(); 

Добавьте код ниже,

 if (isset($_GET['state'])) { $helper->getPersistentDataHandler()->set('state', $_GET['state']); } 

Я получил эту ошибку при использовании SDK Facebook в Symfony2, написав Twig Extension, чтобы отображать данные из API в шаблонах.

Решение для меня заключалось в добавлении 'persistent_data_handler'=>'session' в конфигурацию объекта Facebook, которая заставляет данные состояния храниться в сеансовом ключе вместо памяти:

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

По умолчанию он использовал встроенный обработчик памяти, который не работал должным образом для меня. Возможно, из-за того, что некоторые функции вызываются изнутри Twig Extension, поскольку обработчик памяти работает при использовании SDK исключительно в обычных контроллерах / службах.

По-видимому, состояние устанавливается, когда вы вызываете getLoginUrl() , и извлекается в любое время, когда вы вызываете getAccessToken() . Если сохраненное состояние возвращает значение null (поскольку обработчик данных не является таким постоянным, как это должно быть) проверка проверки CSRF не выполняется.

Если вам нужно обрабатывать сеансы определенным образом или вы хотите сохранить состояние в другом месте, вы также можете написать свой собственный обработчик с помощью функции 'persistent_data_handler' => new MyPersistentDataHandler() , используя в качестве примера функцию FacebookSessionPersistentDataHandler.

Наконец, изучая код FB, я обнаружил, что проблема

Не удалось выполнить проверку подделки на основе перекрестного запроса. Обязательное состояние «состояние» отсутствует

и аналогий вызывается переменной PHP $_SESSION['FBRLH_state'] которая по какой-то «странной» причине, когда FB вызывает файл обратного вызова login.

Чтобы решить эту проблему, я сохраняю эту переменную "FBRLH_state" ПОСЛЕ вызова функции $helper->getLoginUrl(...) . Очень важно делать только после вызова этой функции из-за того, что внутри этой функции находится переменная $_SESSION['FBRLH_state'] .

Ниже пример моего кода в login.php:

 $uri=$helper->getLoginUrl($uri, $permissions); foreach ($_SESSION as $k=>$v) { if(strpos($k, "FBRLH_")!==FALSE) { if(!setcookie($k, $v)) { //what?? } else { $_COOKIE[$k]=$v; } } } var_dump($_COOKIE); 

И в login-callback.php перед вызовом всего кода FB:

 foreach ($_COOKIE as $k=>$v) { if(strpos($k, "FBRLH_")!==FALSE) { $_SESSION[$k]=$v; } } 

И последнее, но не менее важное, помните также, чтобы включить код для сессии PHP, поэтому ..

 if(!session_id()) { session_start(); } ... ... ... ... <?php session_write_close() ?> 

Надеюсь, этот ответ поможет вам сэкономить 8-10 часов работы. Пока, Алекс.

Это происходит, когда библиотека Facebook не может сопоставить параметр состояния, который он получает от Facebook, с тем, который он устанавливает по умолчанию в сеансе. Если вы используете инфраструктуру, такую ​​как Laravel, Yii2 или Kohana, которая реализует собственное хранилище сеансов, стандартная реализация сеанса Facebook, скорее всего, не сработает.

Чтобы исправить это, вам нужно создать свою собственную реализацию PersistentDataInterface используя библиотеку сеансов вашей инфраструктуры, и передать ее конструктору Facebook\Facebook .

Вот пример обработчика упорства Laravel от Facebook :

 use Facebook\PersistentData\PersistentDataInterface; class MyLaravelPersistentDataHandler implements PersistentDataInterface { /** * @var string Prefix to use for session variables. */ protected $sessionPrefix = 'FBRLH_'; /** * @inheritdoc */ public function get($key) { return \Session::get($this->sessionPrefix . $key); } /** * @inheritdoc */ public function set($key, $value) { \Session::put($this->sessionPrefix . $key, $value); } } 

Примеры параметров конструктора:

 $fb = new Facebook\Facebook([ // . . . 'persistent_data_handler' => new MyLaravelPersistentDataHandler(), // . . . ]); 

Подробнее здесь: https://developers.facebook.com/docs/php/PersistentDataInterface/5.0.0

Для меня проблема заключалась в том, что я не запускал сеанс перед сценарием.

Итак, я добавил session_start(); перед созданием класса Facebook .

Эта же проблема возникла у меня на laravel 5.4. Я решил эту проблему, поставив

 session_start(); 

в верхней части скрипта.

Ниже приведен пример пространства имен контроллера laravel, чтобы дать вам пример того, как он будет работать.

 <?php namespace App\Http\Controllers; session_start(); use Facebook\Facebook as Facebook; ?> 

проблема возникает, потому что она еще не началась, добавив начало сеанса в начале скрипта, который мы только начинаем.

надеюсь, что это может помочь кому-то.

вы получаете эту ошибку, если исходное имя хоста отличается от целевого имени хоста после аутентификации.

 $loginUrl = $helper->getLoginUrl('http://MyWebSite', $permissions); 

с этим утверждением, если посетитель на вашем веб-сайте использовал http://www.mywebsite.com/, ошибка межсайтового сайта будет повышена.

Вы должны убедиться, что имя источника и целевое имя хоста точно совпадают, включая возможный префикс www.

Фиксированная версия:

 $loginUrl = $helper->getLoginUrl('http://'.$_SERVER['SERVER_NAME'], $permissions); 

Объект Facebook имеет переменную экземпляра, называемую persistentDataHandler , обычно это экземпляр FacebookSessionPersistentDataHandler , который имеет набор и метод get для доступа к собственным PHP-сессиям.

При генерации URL-адреса обратного вызова с использованием:

 $loginUrl = $helper->getLoginUrl($callback_url, $permissions); 

В методе FacebookRedirectLoginHelper->getLoginUrl() будет создана 32-символьная случайная строка, добавьте ее в $loginUrl и сохраните ее до кода ниже, используя метод set persistentDataHandler .

 $_SESSION['FBRLH_' . 'state'] 

Позже, когда $helper->getAccessToken(); , параметр состояния в URL-адресе будет сравниваться с сохраненным в том же сеансе, чтобы предотвратить CSRF. Если не совпадать, это исключение будет выбрано.

FacebookSDKException : проверка подделки на основе перекрестного запроса не удалась. Обязательное состояние «состояние» отсутствует.

Все это, как говорится, необходимо убедиться, что ваша собственная функция сеанса PHP правильно установлена ​​во время этого процесса. Вы можете проверить это, добавив

 die($_SESSION['FBRLH_' . 'state']); 

после

 $loginUrl = $helper->getLoginUrl($callback_url, $permissions); 

и до

 $accessToken = $helper->getAccessToken(); 

чтобы увидеть, есть ли эта 32-символьная строка.

Надеюсь, поможет!

вы могли бы просто сделать это, чтобы установить сеанс с новым состоянием

 <?php if(isset($_GET['state'])) { if($_SESSION['FBRLH_' . 'state']) { $_SESSION['FBRLH_' . 'state'] = $_GET['state']; } } ?> 

С Symfony это не работает, потому что управление сеансом выполняется.

Чтобы решить проблему, вы можете создать новый обработчик, который будет работать с сеансом symfony.

FacebookDataHandlerSymfony.php:

 <?php use Facebook\PersistentData\PersistentDataInterface; use Symfony\Component\HttpFoundation\Session\Session; class FacebookDataHandlerSymfony implements PersistentDataInterface { private $session; public function __construct() { $this->session = new Session(); } public function get($key) { return $this->session->get('FBRLH_' . $key); } public function set($key, $value) { $this->session->set('FBRLH_' . $key, $value); } } 

И когда вы создаете объект FB, вы должны просто указать новый класс:

 $this->fb = new Facebook([ 'app_id' => '1234', 'app_secret' => '1324', 'default_graph_version' => 'v2.8', 'persistent_data_handler' => new FacebookDataHandlerSymfony() ]); 

Легко исправить для меня. Я изменился:

 $loginUrl = $helper->getLoginUrl('http://www.MYWEBSITE.ca/index_callback.php', $permissions); 

чтобы:

 $loginUrl = $helper->getLoginUrl('http://MYWEBSITE.ca/index_callback.php', $permissions); 

удаление 'www' решило проблему.

В моем случае я проверил ошибку и обнаружил ошибку, которая привела меня к решению с выполнением кода:

 date_default_timezone_set('Europe/Istanbul'); 

перед скриптом. Работал как шарм. Для проверки местоположения: timezones.europe.php

Ошибка запускается, если исходное имя хоста отличается от имени хоста [как указано Souch]. Когда посетители ввели URL-адрес в виде « http://website.com », который отличается от « http://www.website.com ». Мы перенаправляем их на правильный URL, добавляя следующие коды в верхнем положении до session_start ().

  if($_SERVER['HTTP_HOST']!=='www.website.com'){ header('location: http://www.website.com'); } 

Решение Yii2, которое работает для меня:

 use Facebook\PersistentData\PersistentDataInterface; use Yii; class PersistentDataHandler implements PersistentDataInterface { /** * @var string Prefix to use for session variables. */ protected $sessionPrefix = 'FBRLH_'; public function get($key) { return Yii::$app->session->get($this->sessionPrefix . $key); } public function set($key, $value) { Yii::$app->session->set($this->sessionPrefix . $key, $value); } } 

У меня была такая же ошибка, потому что я забыл добавить «www». к адресу отправителя. В настройках Client-OAuth должно быть правильное имя.

Это общая проблема, с которой сталкиваются многие люди в FB Api. это только проблема СЕССИИ. Чтобы решить эту проблему, добавьте некоторый код.

В сценарии обратного вызова обычно fb-callback.php добавляет «session_start ();» перед тем, как вы включите файл автозагрузки facebook. а затем «$ _SESSION ['FBRLH_state'] = $ _ GET ['state'];" после «$ helper = $ fb-> getRedirectLoginHelper ();" линия.

Пример :

 <?php session_start(); include 'vendor/autoload.php'; include 'config.php'; /*Facebook Config*/ $helper = $fb->getRedirectLoginHelper(); $_SESSION['FBRLH_state']=$_GET['state']; try { $accessToken = $helper->getAccessToken(); } ?> 

Может помочь кому-то, кто использует Javascript Helper в интерфейсе для аутентификации пользователя, а в PHP пытается извлечь access_token из Redirect Login Helper . Поэтому используйте следующие

 getJavaScriptHelper(); 

вместо

 getRedirectLoginHelper(); 

РЕШЕНИЕ ДЛЯ ИНТЕРМЕТЕНТНЫХ ПРОБЛЕМ

Я был a) перенаправлением на ссылку для входа в Facebook, b) перенаправление с login.php на main.php. Пользователи перейдут на main.php и несколько других страниц, а затем вернутся обратно в браузере.

В конце концов, они попали бы в login.php с кучей объявленных к нему писем, но Facebook удалил $ _SESSION ['FBRLH_state'] после единственного успеха, так что даже если бы он имел правильное $ _GET ['state'], он бы ошибка.

Решение состоит в том, чтобы: а) отслеживать внутренне, если пользователь вошел в систему и избегал повторной логики Facebook в login.php, ИЛИ b) отслеживать все недавно действительные параметры состояния для этого конкретного пользователя (возможно, на сеансе), которые были установлены Facebook, и если $ _GET ['state'] находится в этом массиве, сделайте следующее:

$ _SESSION ['FBRLH_state'] = $ _GET ['state'];

В этом случае вы можете сделать это безопасно, не нарушая защиту CSRF.

Это может быть немного поздно, но я надеюсь, что это поможет другим, так как эта проблема все еще сохраняется.

У меня была эта проблема некоторое время, и я искал вокруг и видел много разных решений, многие из которых отключили проверку CSRF. Поэтому после всего, что я прочитал, это то, что сработало для меня.

Насколько я понимаю, вы получаете эту ошибку, если ваш URL-адрес перенаправления не соответствует настройке вашего приложения, поэтому моя проблема была исправлена ​​каждый раз, но я также видел, что у людей проблемы, не начав свою сессию должным образом, поэтому Я расскажу обо всех этих проблемах.

Шаг 1. Убедитесь, что сеанс запущен, когда это необходимо.

например: fb-config.php

 session_start(); include_once 'path/to/Facebook/autoload.php'; $fb = new \Facebook\Facebook([ 'app_id' => 'your_app_id', 'app_secret' => 'your_secret_app_id', 'default_graph_version' => 'v2.10' ]); $helper = $fb->getRedirectLoginHelper(); 

если ваш код обратного вызова facebook находится в другом файле, кроме конфигурации, запустите сеанс и в этом файле.

например: fb-callback.php

 session_start(); include_once 'path/to/fb-config.php'; try { $accessToken = $helper->getAccessToken(); } catch (\Facebook\Exceptions\FacebookResponseException $e) { echo "Response Exception: " . $e->getMessage(); exit(); } catch (\Facebook\Exceptions\FacebookSDKException $e) { echo "SDK Exception: " . $e->getMessage(); exit(); } /** THE REST OF YOUR CALLBACK CODE **/ 

Теперь, что решило мою актуальную проблему.

Шаг 3. Настройте URL-адрес перенаправления в настройках вашего приложения.

В настройках вашего приложения для входа в Facebook перейдите в URI с приоритетом OUuth, где вы должны добавить URL-адрес, указывающий на ваш файл fb-callback.php.

 http://example.com/fb-callback.php AND ALSO http://www.example.com/fb-callback.php 

затем настройте URL-адрес перенаправления следующим образом.

 $redirectURL = "http://".$_SERVER['SERVER_NAME']."/fb-callback.php"; $permissions = ['email']; $fLoginURL = $helper->getLoginUrl($redirectURL, $permissions); 

Почему с WWW и без www и зачем использовать SERVER_NAME?

потому что ваш действительный URI перенаправления UA должен соответствовать вашему URL-адресу перенаправления в вашем коде, и если в настройках вашего приложения вы установите только перенаправление OAuth как http://example.com/fb-callback.php и настройте свой $ redirectURL как http: //example.com/fb-bacllback.php, чтобы он совпал, но пользователь вошел в ваш сайт как http://www.example.com, тогда пользователь получит сообщение об ошибке SDK для Facebook: проверка подделки на основе перекрестного запроса не удалась. Требуемое «состояние состояния» отсутствует из постоянных данных, потому что URL-адрес пользователя находится, не ТОЧНО соответствует тому, что вы настроили. Зачем? У меня нет волнующей идеи.

Мой подход делает это так, если пользователь вводит ваш сайт как http://example.com или http://www.example.com , он всегда будет соответствовать настройкам вашего приложения. Зачем? потому что $ _SERVER ['SERVER_NAME'] вернет домен с или без www в зависимости от того, как пользователь вводил URL-адрес в браузере.

Это мои выводы, и это единственное, что сработало для меня, не снимая проверку CSRF и до сих пор никаких проблем.

Надеюсь, это поможет.

Для меня настройка состояния сеанса

Полный код (в URL-адресе redirect url)

 $accessToken = ''; $helper = $fb->getRedirectLoginHelper(); if(isset($_GET['state'])){ $_SESSION['FBRLH_state']=$_GET['state']; } try { $accessToken = $helper->getAccessToken(); } catch ( Facebook\Exceptions\FacebookResponseException $e ) { // When Graph returns an error echo 'Graph returned an error: ' . $e->getMessage(); } 

Для меня проблема была другая; (Я был глупым). У меня появилось всплывающее окно с входом в Facebook и снова кнопки входа в систему Facebook на странице входа / регистрации.

  • Всякий раз, когда я нажимаю кнопку Facebook в всплывающем окне с других страниц, он отлично работает.
  • Но, когда я нажимаю кнопку Facebook во всплывающем окне со страницы входа / регистрации, это не сработает.

Причина в том, что я повторно создал объекты Facebook и getRedirectLoginHelper. Я должен был прокомментировать эти заявления на страницах входа / регистрации, поскольку он уже был доступен.

 $_SESSION['FBRLH_state']=$_GET['state']; 

это не путь. Хотя это сработало.

см. «default_graph_version» на всех страницах, если вы измените, а затем сохраните их правильно, это отображается в https://developers.facebook.com/apps/