Я сделал очень простой PHP-скрипт, просто чтобы попытаться войти через Facebook и получить accessToken. Но когда я пытаюсь использовать следующий код, я получаю исключение из SDK: «Ошибка проверки подделки на основе межсайтового запроса не удалась. Обязательное состояние «состояние» отсутствует. ».
Вот мой код:
require_once __DIR__ . '/facebook-sdk-v5/autoload.php'; session_start(); $fb = new Facebook\Facebook([ 'app_id' => '{my-own-app-id}', 'app_secret' => '{my-own-app-secret}' ]); // Check to see if we already have an accessToken ? if (isset($_SESSION['facebook_access_token'] )) { $accessToken = $_SESSION['facebook_access_token']; echo "Horray we have our accessToken:$accessToken<br />\n"; } else { // We don't have the accessToken // But are we in the process of getting it ? if (isset($_REQUEST['code'])) { $helper = $fb->getRedirectLoginHelper(); try { $accessToken = $helper->getAccessToken(); } 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)) { // Logged in! $_SESSION['facebook_access_token'] = (string) $accessToken; // Now you can redirect to another page and use the // access token from $_SESSION['facebook_access_token'] echo "Finally logged in! Token:$accessToken"; } } else { // Well looks like we are a fresh dude, login to Facebook! $helper = $fb->getRedirectLoginHelper(); $permissions = ['email', 'user_likes']; // optional $loginUrl = $helper->getLoginUrl('http://mywebsite.com/myapp/index.php', $permissions); echo '<a href="' . $loginUrl . '">Log in with Facebook!</a>'; } } exit;
Мне пришлось добавлять эти строки на некоторых серверах:
$helper = $fb->getRedirectLoginHelper(); if (isset($_GET['state'])) { $helper->getPersistentDataHandler()->set('state', $_GET['state']); }
Я получаю эту ошибку случайным образом, в зависимости от конфигурации сервера.
Если вы используете «www» версию своего сайта для создания ссылки для входа в систему, и вы перенаправляетесь на версию, отличную от www, вы столкнетесь с проблемами со своей сессией. Поэтому убедитесь, что вы открыли www-версию своего сайта, а затем определили URL-адрес обратного вызова в той же версии www. Кроме того, вы можете определить постоянные переадресации в конфигурации вашего сервера, чтобы убедиться, что любой доступ к вашему сайту из версии, отличной от www, перенаправляется на версию www или наоборот.
session_start () в начале обоих скриптов. Я получил решение отсюда: https://github.com/facebook/facebook-php-sdk-v4/issues/473
вы получаете эту ошибку, если исходное имя хоста отличается от целевого имени хоста после аутентификации.
$loginUrl = $helper->getLoginUrl('http://mywebsite.com/myapp/index.php', $permissions);
с этим утверждением, если посетитель на вашем веб-сайте использовал http://www.mywebsite.com/, ошибка межсайтового сайта будет повышена.
Вы должны убедиться, что имя источника и целевое имя хоста точно совпадают, включая возможный префикс www.
Фиксированная версия:
$loginUrl = $helper->getLoginUrl('http://'.$_SERVER['SERVER_NAME'].'/myapp/index.php', $permissions);
Я столкнулся с подобной проблемой и нашел решение Nanang Koesharwanto. Это больше похоже на quirk, поскольку изменение исходных файлов в каталоге поставщиков – очень плохая идея. Итак, вот трюк.
public function callback(Request $request) { $this->helper->getPersistentDataHandler()->set('state', $request->state); return $this->helper->getAccessToken(); }
Если это не удается, use Session;
в вашем контроллере.
Я также столкнулся с одной и той же проблемой, и после изучения строки ввода stackoverflow
$_SESSION['FBRLH_state']=$_GET['state'];
выше решила мою проблему
$helper = $fb->getRedirectLoginHelper();
Установка [PersistentDataHandler] явно до получения ваших токенов гарантирует, что запрос будет успешным. Ниже показано, как получить $ _GET ['state'] и просто ввести его в «для использования [помощник]» на Symfony 2.x | 3.x
У меня была такая же проблема, как и у OP, и это устранило мою проблему.
//create your new facebook sdk instance $this->fb = new Facebook([ 'app_id' => $facebookAppId, 'app_secret' =>$facebookAppSecret, 'default_graph_version' =>$facebookDefaultGraphVersion ]); //retrieve the helper $this->helper = $this->fb->getRedirectLoginHelper(); //below is the money shot //setting this explicitly before you get your tokens will guarantee that the request will be a success. It Fetches $_GET['state'] & simply injects it into the "to be used [helper]" $this->helper->getPersistentDataHandler()->set('state', $request->query->get('state'));
Для меня проблема решена сейчас, только запустив сеанс, добавив следующее:
session_start();
в начале обоих файлов (первый файл, генерирующий URL-адрес facebook и файл обратного вызова: login.php и fb-callback.php ( https://developers.facebook.com/docs/php/howto/example_facebook_login )).
Мне также пришлось добавить следующее:
$config['app_id'] = 'myapp_id';
вверху, чтобы предотвратить другую не связанную ошибку.
Как я ответил здесь: Facebook SDK вернул ошибку: проверка подделки на основе перекрестного запроса не удалась. Параметр «состояние» из URL-адреса и сеанса не соответствует
вам необходимо убедиться, что ваша собственная функция сеанса PHP правильно установлена.
Laravel 5.2
У меня тоже есть эта ошибка. Ошибка проверки подделки на основе межсайтового запроса. Обязательное состояние параметра «отсутствует».
и после прочтения этого часами. Я попытался изменить сценарий поставщика.
в vendor\facebook\php-sdk-v4\src\Facebook\Helpers\FacebookRedirectLoginHelper.php
в строке 123, я меняю этот скрипт:
private function makeUrl($redirectUrl, array $scope, array $params = [], $separator = '&') { $state = $this->pseudoRandomStringGenerator->getPseudoRandomString(static::CSRF_LENGTH); $this->persistentDataHandler->set('state', $state); return $this->oAuth2Client->getAuthorizationUrl($redirectUrl, $state, $scope, $params, $separator); }
в (я добавляю Session::put('state', $state);
)
private function makeUrl($redirectUrl, array $scope, array $params = [], $separator = '&') { $state = $this->pseudoRandomStringGenerator->getPseudoRandomString(static::CSRF_LENGTH); $this->persistentDataHandler->set('state', $state); Session::put('state', $state); return $this->oAuth2Client->getAuthorizationUrl($redirectUrl, $state, $scope, $params, $separator); }
и в строке 234 я изменяю этот скрипт:
protected function validateCsrf() { $state = $this->getState(); $savedState = $this->persistentDataHandler->get('state'); if (!$state || !$savedState) { throw new FacebookSDKException('Cross-site request forgery validation failed. Required param "state" missing.'); } $savedLen = strlen($savedState); $givenLen = strlen($state); if ($savedLen !== $givenLen) { throw new FacebookSDKException('Cross-site request forgery validation failed. The "state" param from the URL and session do not match.'); } $result = 0; for ($i = 0; $i < $savedLen; $i++) { $result |= ord($state[$i]) ^ ord($savedState[$i]); } if ($result !== 0) { throw new FacebookSDKException('Cross-site request forgery validation failed. The "state" param from the URL and session do not match.'); } }
в (я добавил $this->persistentDataHandler->set('state', Session::get('state'));
)
protected function validateCsrf() { $state = $this->getState(); $this->persistentDataHandler->set('state', Session::get('state')); $savedState = $this->persistentDataHandler->get('state'); if (!$state || !$savedState) { throw new FacebookSDKException('Cross-site request forgery validation failed. Required param "state" missing.'); } $savedLen = strlen($savedState); $givenLen = strlen($state); if ($savedLen !== $givenLen) { throw new FacebookSDKException('Cross-site request forgery validation failed. The "state" param from the URL and session do not match.'); } $result = 0; for ($i = 0; $i < $savedLen; $i++) { $result |= ord($state[$i]) ^ ord($savedState[$i]); } if ($result !== 0) { throw new FacebookSDKException('Cross-site request forgery validation failed. The "state" param from the URL and session do not match.'); } }
это все, что я сделал. и ошибка исчезла.
Это общая проблема, с которой сталкиваются многие люди в FB Api. это только проблема СЕССИИ. Чтобы решить эту проблему, добавьте некоторый код.
В сценарии обратного вызова обычно fb-callback.php добавляет «session_start ();» перед тем, как вы включите файл автозагрузки facebook. а затем «$ _SESSION ['FBRLH_state'] = $ _ GET ['state'];" после «$ helper = $ fb-> getRedirectLoginHelper ();" линия.
Пример :
<?php session_start(); /*Add session start*/ include 'vendor/autoload.php'; include 'config.php'; /*Facebook Config*/ $helper = $fb->getRedirectLoginHelper(); $_SESSION['FBRLH_state']=$_GET['state']; /*Add This*/ try { $accessToken = $helper->getAccessToken(); } ?>
Реальная проблема здесь заключалась в кодировании моего PHP-файла. Я использовал UTF8, но это должен был быть UTF8 без спецификации.
Побочным эффектом неправильного кодирования было то, что моя сессия не работала должным образом, а затем SDK не смог получить необходимую информацию для правильной работы.
Правильно сконфигурированное сообщение об ошибках должно было бы сказать, что проблема была прямой.
Я думаю, что мы можем заполнить эту ошибку в категории «noob». Но все же, я думаю, что это может быть полезно для других нубов, подобных мне.
Наконец, изучая 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 часов работы. Пока, Алекс.
вы должны убедиться, что сеанс начинается до запуска скрипта. но снова он будет генерировать 443: Network is unreachable
если вы снова начнете сеанс по тому же сценарию. надеюсь, это поможет кому-то.
Я просто использовал if (session_status() == PHP_SESSION_NONE){ session_start(); }
if (session_status() == PHP_SESSION_NONE){ session_start(); }
Тем из вас, кто использует cakephp 3.x и у вас есть эта проблема, и вы не знаете, как ее решить. Добавить session_start (); в начале вашего метода auth и callback.
public function Facebookauth() { session_start(); $fb = new Facebook([ 'app_id' => '{app_id}', 'app_secret' => '{app_secret}', 'default_graph_version' => 'v2.6', .......... ]); you can still use $session = $this->request->session();
Для меня это происходило из-за «persistent_data_handler» . Добавив это в конфигурацию Facebook, я смог заставить его работать.
session_start(); $fb = new Facebook\Facebook([ 'app_id' => '6XXXXXXXXX', 'app_secret' => '5XXXXXXXXXXXXXX', 'default_graph_version' => 'v2.6', 'persistent_data_handler' => 'session' ]);
Исправление для меня состояло в том, чтобы изменить 'secure' => true
на false
в config / session.php. Я случайно установил это в true, не используя https в первую очередь.
Для меня решение ломало исключение, заменив namespaced Facebook\Exceptions\FacebookSDKException
на просто Exception
, потому что скрипт уже использовал его.
use Facebook\Facebook; // code ... $fb = new Facebook([ 'app_id' => FB_APP_ID, 'app_secret' => FB_APP_SECRET, 'default_graph_version' => 'v2.5', ]); $helper = $fb->getRedirectLoginHelper(); try { $accessToken = $helper->getAccessToken(); } catch (Exception $e) { echo $e->getMessage(); exit; }
Я пытался внедрить вход в Facebook в Symfony с помощью PHP PHP SDK, и у меня была такая же ошибка. Ошибка проверки подделок на основе межсайтового запроса. Обязательное состояние параметра «отсутствует» .
Я решил проблему, добавив параметр persistent_data_handler к моему instanciation приложения facebook с помощью специального обработчика, который реализует PersistentDataInterface из PHP PHP SDK.
Работает как шарм.
public function facebookCallbackAction(Request $request) { $session = $request->getSession(); $fb = new \Facebook\Facebook([ 'app_id' => $this->container->getParameter('facebook_app_id'), 'app_secret' => $this->container->getParameter('facebook_app_secret'), 'default_graph_version' => 'v2.5', 'persistent_data_handler' => new SymfonyPersistentDataHandler($session), ]); }
Мой пользовательский обработчик:
use Facebook\PersistentData\PersistentDataInterface; use Symfony\Component\HttpFoundation\Session\Session; class SymfonyPersistentDataHandler implements PersistentDataInterface { protected $session; protected $sessionPrefix = 'FBRLH_'; public function __construct(Session $session) { $this->session = $session; } public function get($key) { return $this->session->get($this->sessionPrefix . $key); } public function set($key, $value) { $this->session->set($this->sessionPrefix . $key, $value); } }
Наконец, после всех этих приятных ошибок, я устранил все свои проблемы с другим решением, пример из документов разработчиков facebook устарел.
SDK V5 и APi 2.4 работают так, как описано в этом учебном пособии , необходимо определить токен доступа
Обязательно заполните APP-IP | APP-SECRET своими учетными данными .
Пример из учебника:
$fb = new Facebook\Facebook([ 'app_id' => 'APP-ID', 'app_secret' => 'APP-SECRET', 'default_graph_version' => 'v2.4', 'default_access_token' => 'APP-ID|APP-SECRET' ]);
Используйте это, а не пример в документах разработчика facebook.
Повеселись 🙂
Что бы ты не делал. Просто не называйте getAccessToken () более одного раза. Он удаляет состояние из сеанса, как только он вызывается.