我做了一个非常简单的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;
答案 0 :(得分:23)
我必须在某些服务器中添加这些行:
$helper = $fb->getRedirectLoginHelper();
if (isset($_GET['state'])) {
$helper->getPersistentDataHandler()->set('state', $_GET['state']);
}
我随机收到此错误,具体取决于服务器配置。
答案 1 :(得分:9)
如果您使用网站的“www”版本生成登录链接,并且您被重定向到非www版本,则会遇到会话问题。因此,请确保您访问您网站的www版本,然后将回调网址定义为相同的www版本。此外,您可以在服务器配置中定义永久重定向,以确保从非www版本访问您网站的任何人都被重定向到www版本,反之亦然。
答案 2 :(得分:9)
session_start()。我从这里得到了解决方案:https://github.com/facebook/facebook-php-sdk-v4/issues/473
答案 3 :(得分:3)
在研究stackoverflow之后,我也遇到了同样的问题 放线
$_SESSION['FBRLH_state']=$_GET['state'];
以上解决了我的问题
$helper = $fb->getRedirectLoginHelper();
答案 4 :(得分:2)
如果源主机名与经过身份验证的目标主机名不同,则会收到此错误。
$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);
答案 5 :(得分:2)
这是很多人在FB Api面临的常见问题。这只是一个SESSION问题。要解决此问题,请添加一些代码,例如。
在回调脚本上通常fb-callback.php add&#34; session_start();&#34;就在你加入facebook自动加载文件之前。然后&#34; $ _ SESSION [&#39; FBRLH_state&#39;] = $ _ GET [&#39; state&#39;];&#34; &#34; $ helper = $ fb-&gt; getRedirectLoginHelper();&#34;线。
示例:
<?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();
} ?>
答案 6 :(得分:2)
在获得令牌之前明确设置[PersistentDataHandler]将保证请求成功。下面显示了如何获取$ _GET [&#39; state&#39;]&amp;只需将其注入&#34;即可使用[帮助者]&#34;在Symfony 2.x上3.X
我有与O.P.完全相同的问题,这解决了我的问题。
//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'));
答案 7 :(得分:1)
对我来说,问题现在只需通过添加以下内容来启动会话即可解决:
session_start();
在两个文件的开头(第一个文件生成facebook url和回调文件:login.php和fb-callback.php(https://developers.facebook.com/docs/php/howto/example_facebook_login))。
我还必须补充一下:
$config['app_id'] = 'myapp_id';
位于顶部,以防止出现其他非相关错误。
答案 8 :(得分:1)
您需要确保正确设置了本机PHP会话功能。
答案 9 :(得分:1)
我试图用Facebook PHP SDK在Symfony中实现Facebook登录,我遇到了同样的错误&#34;跨站点请求伪造验证失败。必需的参数“状态”缺失&#34; 。
我通过使用自定义处理程序将 persistent_data_handler 参数添加到我的facebook app instanciation来解决了这个问题,该处理程序实现了Facebook PHP SDK的PersistentDataInterface。
像魅力一样。
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);
}
}
答案 10 :(得分:1)
我遇到了类似的问题,发现了Nanang Koesharwanto的解决方案。它更像是quirk,因为在供应商目录中修改源文件是一个非常坏主意。 所以这就是诀窍。
public function callback(Request $request)
{
$this->helper->getPersistentDataHandler()->set('state', $request->state);
return $this->helper->getAccessToken();
}
如果失败,请将use Session;
放入控制器。
答案 11 :(得分:0)
我通过在Facebook开发者帐户的“ Facebook->登录->有效OAuth重定向URI”中设置回叫网址来解决此错误。
答案 12 :(得分:0)
这里真正的问题是我的PHP文件的编码。我使用的是UTF8,但它应该是没有BOM的UTF8。
错误编码的副作用是我的SESSION无法正常工作,然后SDK无法检索必要的信息才能正常工作。
正确配置的错误报告会告诉我直接存在问题。
我认为我们可以填补&#34; noob&#34;类别。但是,我认为它对我这样的其他新手也很有用。
答案 13 :(得分:0)
如果session_start()仍不能解决问题,则您在Facebook开发人员应用的有效OAuth重定向URI中输入了错误的URI。
解决: 首先,转到fb-callback.php,找到您放入标头函数中的URI,例如:header(“ Location:https://localhost/home.php”)。然后转到您的Facebook开发人员应用程序,然后在边栏中单击“产品”选项卡下的Facebook登录,然后单击“设置”。在有效的OAuth重定向URI中,添加您放入标头中的URI。从我的示例中,我将放https://localhost/home.php。
希望这会有所帮助。
答案 14 :(得分:0)
对我来说,解决方案是通过将命名空间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;
}
答案 15 :(得分:0)
我的修复方法是在config / session.php中将'secure' => true
更改为false
。
我在第一时间没有使用https时意外地将其设置为true。
答案 16 :(得分:0)
对我来说,由于&#39; persistent_data_handler&#39; ,这种情况正在发生。通过在Facebook配置中添加它,我能够使它工作。
session_start();
$fb = new Facebook\Facebook([
'app_id' => '6XXXXXXXXX',
'app_secret' => '5XXXXXXXXXXXXXX',
'default_graph_version' => 'v2.6',
'persistent_data_handler' => 'session'
]);
答案 17 :(得分:0)
对于那些使用cakephp 3.x并且遇到此问题并且您不知道如何解决它的人。 添加session_start();在您的身份验证和回调方法的开头。
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();
答案 18 :(得分:0)
Laravel 5.2
我也有这个错误“跨站点请求伪造验证失败。必需的参数”状态“丢失”。
并在阅读this几个小时之后。我试图更改供应商脚本。
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.');
}
}
这就是我所做的一切。并且错误消失了。
答案 19 :(得分:0)
您必须确保会话在脚本运行之前启动。但如果再次在同一个脚本上启动会话,它将再次抛出443: Network is unreachable
。希望这对某人有所帮助。
我刚刚用过
if (session_status() == PHP_SESSION_NONE){ session_start(); }
答案 20 :(得分:0)
最后,看一下FB代码,我发现问题“跨站点请求伪造验证失败。必需的参数”状态“缺失”和类似物是由PHP变量$ _SESSION ['FBRLH_state']引起的,对于某些“奇怪” “当FB调用login-callback文件时的原因。
为了解决这个问题,我在调用函数$ helper-&gt; getLoginUrl(...)之后存储了这个变量“FBRLH_state”。只有在调用此函数后才能执行此操作,因为当填充变量$ _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);
在调用所有FB代码之前的login-callback.php中:
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个小时的工作:) 再见,亚历克斯。
答案 21 :(得分:-1)
无论你做什么。只是不要多次调用getAccessToken()。它会在调用后立即从会话中删除状态。
答案 22 :(得分:-1)
最后在所有这些不错的错误之后, 我用另一个解决方案解决了所有问题, 来自facebook开发者文档的示例已过时。
SDK V5和APi 2.4 与[{3}} 中描述的一样有效 需要定义访问令牌
请务必使用您的凭据填写 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 docs上的示例。
玩得开心:)