Facebook SDK error: Cross-site request forgery validation failed. Required param "state" missing from persistent data
Facebook SDK error: Cross-site request forgery validation failed. Required param "state" missing from persistent data
我最近升级到最新版本的 facebook SDK,我在登录用户时遇到问题。我生成登录 link 很好,但是当 facebook 将用户发送回我的网站时令牌,我收到此错误:
fb sdk错误:跨站请求伪造验证失败。持久数据中缺少必需的参数 "state"。
我试着解决了一些问题。我打印出了会话数据中的所有内容以及 GET 请求中的所有内容。我看到 GET 有一个状态参数,会话数据有一个 FBRLH_state 参数。它们都具有相同的值。那它怎么告诉我参数丢失了?
我已经尝试了一些我在其他问题上看到的建议(即开始会话),但似乎没有任何效果。
如有任何帮助,我们将不胜感激!我正在使用 php-graph-sdk-5.5。我的 facebook 连接文件如下
if(!class_exists('facebook')){
class facebook{
private $db = null;
private $fb = null;
private $token = null;
private $DEV = null;
private $sdk_error = null;
private $api_error = null;
private $verbose = false;
private $graph_user = null;
private $db_helper = null;
private $errors = null;
public function __construct($db,
$fb_id = FB_APP_ID,
$fb_secret = FB_APP_SECRET,
$fb_version = FB_DEFAULT_GRAPH_VERSION){
if($this->verbose) echo '<pre>';
if($this->verbose) echo 'starting construction'.PHP_EOL;
$this->db = $db;
if(!$this->fb){
$this->log[] = 'no connect found. building..'.PHP_EOL;
$this->fb = new Facebook\Facebook(array(
'app_id' => $fb_id,
'app_secret' => $fb_secret,
'default_graph_version' => $fb_version));
if(!$this->fb){
die('facebook initialization failure');
}
$this->log[] = 'finished building new connection'.PHP_EOL;
}
}
public function get_login_url($callback_uri, $permissions = ['email','user_birthday']){
global $_DEV,$_config;
$helper = $this->fb->getRedirectLoginHelper();
$callback_host = ($_DEV ? $_config['dev_domain'] : $_config['live_domain']);
$callback_url = 'https://'.$callback_host.$callback_uri;
return $helper->getLoginUrl($callback_url, $permissions);
}
public function catch_token(){
if($this->token){
$this->log[] = 'already have token.'.PHP_EOL;
return $this->token;
} else if(!$this->fb){
$this->log[] = $this->error[] = 'no facebook connection in catch token()';
}
$this->log[] = 'starting catch token routine.'.PHP_EOL;
//$_SESSION['state']=$_GET['state'];
echo '<pre>' . var_export($_SESSION, true) . '</pre>';
echo '<BR><BR><pre>' . var_export($_GET, true) . '</pre>';
$helper = $this->fb->getRedirectLoginHelper();
$this->token = $helper->getAccessToken();
$this->log[] = 'caught token: '.$this->token;
$string_token = $this->token.PHP_EOL;
//die($string_token);
try {
$helper = $this->fb->getRedirectLoginHelper();
$this->token = $helper->getAccessToken();
$this->log[] = 'caught token: '.$this->token;
$string_token = $this->token.PHP_EOL;
return $this->user_flush();
} catch(Facebook\Exceptions\FacebookResponseException $e) {
// When Graph returns an error
$this->log[] = $this->errors[] = 'fb api error: ' . $e->getMessage();
return null;
} catch(Facebook\Exceptions\FacebookSDKException $e) {
// When validation fails or other local issues
$this->log[] = $this->errors[] = 'fb sdk error: ' . $e->getMessage();
return null;
} catch(Exception $e){
$this->log[] = $this->errors[] = 'unknown error: '.$e->getMessage();
return null;
}
}
public function get_token(){
$this->log[] = 'get token called.'.PHP_EOL;
if($this->token){
$this->log[] = 'token found in object'.PHP_EOL;
//echo '<pre>';
//die(debug_print_backtrace());
return $this->token;
} else {
$this->log[] = $this->errors[] = 'token not found in object.'.PHP_EOL;
return null;
}
}
public function get_user($override = false){
$fields = array(
'first_name',
'last_name',
'email',
'id',
'picture',
'birthday',
'gender',);
$fields = implode(',',$fields);
if($this->graph_user === null){
if($this->fb && $this->get_token()){
try {
// Returns a Facebook\FacebookResponse object
$resp_url = '/me?fields='.$fields.'&debug=all';
$this->log[] = $resp_url;
$response = $this->fb->get($resp_url, $this->get_token());
$this->graph_user = $response->getGraphUser();
return $this->graph_user;
}
catch(Facebook\Exceptions\FacebookResponseException $e) {
// When Graph returns an error
$this->api_error = 'fb api error: ' . $e->getMessage();
$this->errors[] = $this->api_error;
return null;
}
catch(Facebook\Exceptions\FacebookSDKException $e) {
// When validation fails or other local issues
$this->sdk_error = 'fb sdk error: ' . $e->getMessage();
$this->errors[] = $this->sdk_error;
return null;
}
} else {
$this->sdk_error = "get_user(): fb connection or token not set. are you logged in?";
$this->errors[] = $this->sdk_error;
//echo '<pre>';
//debug_print_backtrace();
//die('token: '.$this->token);
return null;
}
} else {
$this->sdk_error = "get_user(): graph_user already set";
$this->errors[] = $this->sdk_error;
return $this->graph_user;
}
}
public function get_user_first_name(){
return $this->get_user()['first_name'];
}
public function get_user_last_name(){
return $this->get_user()['last_name'];
}
public function get_user_id(){
return $this->get_user()['id'];
}
public function get_user_email(){
return $this->get_user()['email'];
}
public function get_user_picture(){
return $this->get_user()['picture']['url'];
}
public function get_user_birthday(){
return $this->get_user()['birthday'];
}
public function user_flush(){
//this is the command function.
// runs the basic functionality of this class
// by adding this user to the database if they're not there
// and logging them in if they are.
$this->graph_user = $this->get_user();
//$this->log['graph_user_at_user_flush'] = $this->graph_user;
$this->build_user();
$this->log['GRAPH_USER'] = $this->get_user();
$this->log['user_input_array@user_flush'] = $this->user_input;
if($return = $this->user->fb_register()){
//die(print_r(debug_backtrace(),true));
//$this->log['success return'] = '. '.$return;
return $return;
} else {
//die('<pre>'.print_r(debug_backtrace(),true));
$this->log['fb_register_fail'] = array('fb_register() (also login) failed.',$this->user->get_errors());
return null;
}
}
public function build_user(){
$this->user_input['first_name'] = $this->get_user_first_name();
//$this->user_input['last_name'] = $this->get_user_last_name();
$this->user_input['facebook_id'] = $this->get_user_id();
$this->user_input['email'] = $this->get_user_email();
$this->user_input['image_url'] = $this->get_user_picture();
$this->user_input['birthday'] = $this->get_user_birthday();
if($this->verbose)
print_r($this->user_input);
$this->user = new user($this->user_input,$this->db);
}
public function logout(){
unset($_SESSION['fb_id']);
unset($this->token);
unset($this->fb);
}
public function get_errors(){
return array_unique($this->errors);
}
public function get_log(){
return array_unique($this->log);
}
}
}
//finally, create the connection.
if(!isset($fb))
$fb = new facebook($db);
fb sdk error: Cross-site request forgery validation failed. Required param "state" missing from persistent data.
这与您正在执行两次调用 getRedirectLoginHelper 和 $helper->getAccessToken() 的例程有关 - 一次 "on their own",然后在 try-catch 块中再次调用(复制和粘贴错误,或者不幸的调试尝试?)
我现在有点懒得去查看 SDK 源代码,但我认为它在代码交换令牌后故意取消设置会话中的状态参数,作为使整个过程更容易的一部分安全 - 这样当您第二次调用 getAccessToken 时,它就会失败。
这可能有点晚了,但我希望它对其他人有所帮助。
我遇到这个问题有一段时间了,我四处搜索并看到了很多不同的解决方案,其中许多都禁用了 CSRF 检查。所以在我阅读了所有内容之后,这对我有用。
据我了解,当您的重定向 URL 与您在应用程序设置中设置的重定向不匹配时,您会收到此错误,因此我的问题很容易解决,但我也看到有人遇到问题由于他们的 session 没有正常启动,所以我将涵盖这两个问题。
第 1 步:确保您的 session 已在需要时启动。
例如: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 回调代码在配置之外的另一个文件中,那么也在该文件上启动 session。
例如: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 登录应用程序设置中,转到 有效的 OAuth 重定向 URI,您应该在其中添加指向您的 fb-callback 的 url。 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,以及为什么使用 SERVER_NAME?
因为您的有效的 OAuth 重定向 URI 需要与代码中的重定向 url 匹配,如果在您的应用程序设置中您只将 OAuth 重定向设置为 http://example.com/fb-callback.php and set up your $redirectURL as http://example.com/fb-bacllback.php to make it match but the user entered your site as http://www.example.com 那么用户将收到 Facebook SDK 错误:Cross-site 请求伪造验证失败。持久数据 中缺少必需的参数“state”,因为 URL 用户所在的位置与您的设置不完全匹配。为什么?我不知道。
我的方法是这样的,如果用户以 http://example.com or http://www.example.com 的身份进入您的网站,它将始终与您在应用设置中的设置相匹配。为什么?因为 $_SERVER['SERVER_NAME'] 将 return 带或不带 www 的域取决于用户在浏览器中输入 url 的方式。
这是我的发现,这是唯一没有删除 CSRF 检查对我有用的东西,到目前为止,没有任何问题。
希望对您有所帮助。
如果有人仍然遇到这个问题,只需在回调文件的开头添加一个 session_start()
。
点击登录后还是出现这个错误..
SDK Exception: Cross-site request forgery validation failed. Required
param "state" missing from persistent data.
我就跟着看之前的话题和上面的评论。并仔细检查 URL 有效的 OAuth 重定向 URI。
这是我所做的。非常感谢您能分享一些想法并纠正我..
创建-acc.php
///FACEBOOK SIGNUP
session_start();
include_once 'config-facebook.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();
}
$redirectURL = "http://".$_SERVER['SERVER_NAME']."/create-acc.php";
$permissions = ['email'];
$fLoginURL = $helper->getLoginUrl($redirectURL, $permissions);
$facebook_button ='
<div style="background-color:white; color:#4b5563; cursor:pointer;" class="inline-flex border-2 py-1.5 px-5 rounded text-lg border-gray-300">
<div style="margin-top:5px;">
<img style="width:25px;" src="./assets/apps/facebook-logo-2019.png"/>
</div>
<a href="'.$fLoginURL.'" style="margin:5px 10px;"><b>Sign up with Facebook</b></a>
</div>
';
配置-facebook.php
include_once 'Facebook/autoload.php';
$fb = new \Facebook\Facebook([
'app_id' => '**************',
'app_secret' => '*************',
'default_graph_version' => 'v2.10'
]);
$helper = $fb->getRedirectLoginHelper();
我真的是这个编程的新手,并且还在学习。所以如果你帮助它真的节省了我的时间并学习提供的 codes.And 如果我试图添加一些回调代码来获取数据,它在我的工作中看起来像这样
create-acc.php 添加回调代码
///FACEBOOK SIGNUP
session_start();
include_once 'config-facebook.php';
if (isset($accessToken))
{
if (!isset($_SESSION['facebook_access_token']))
{
//get short-lived access token
$_SESSION['facebook_access_token'] = (string) $accessToken;
//OAuth 2.0 client handler
$oAuth2Client = $fb->getOAuth2Client();
//Exchanges a short-lived access token for a long-lived one
$longLivedAccessToken = $oAuth2Client->getLongLivedAccessToken($_SESSION['facebook_access_token']);
$_SESSION['facebook_access_token'] = (string) $longLivedAccessToken;
//setting default access token to be used in script
$fb->setDefaultAccessToken($_SESSION['facebook_access_token']);
}
else
{
$fb->setDefaultAccessToken($_SESSION['facebook_access_token']);
}
if (isset($_GET['code']))
{
header('Location: ./');
}
try {
$fb_response = $fb->get('/me?fields=name,first_name,last_name,email');
$fb_response_picture = $fb->get('/me/picture?redirect=false&height=200');
$fb_user = $fb_response->getGraphUser();
$picture = $fb_response_picture->getGraphUser();
$_SESSION['fb_user_id'] = $fb_user->getProperty('id');
$_SESSION['fb_user_name'] = $fb_user->getProperty('name');
$_SESSION['fb_user_email'] = $fb_user->getProperty('email');
$_SESSION['fb_user_pic'] = $picture['url'];
} catch(Facebook\Exceptions\FacebookResponseException $e) {
echo 'Facebook API Error: ' . $e->getMessage();
session_destroy();
header("Location: ./");
exit;
} catch(Facebook\Exceptions\FacebookSDKException $e) {
echo 'Facebook SDK Error: ' . $e->getMessage();
exit;
}
}
else
{
$redirectURL = "http://".$_SERVER['SERVER_NAME']."/create-acc.php";
$permissions = ['email'];
$fLoginURL = $helper->getLoginUrl($redirectURL, $permissions);
$facebook_button ='
<div style="background-color:white; color:#4b5563; cursor:pointer;" class="inline-flex border-2 py-1.5 px-5 rounded text-lg border-gray-300">
<div style="margin-top:5px;">
<img style="width:25px;" src="./assets/apps/facebook-logo-2019.png"/>
</div>
<a href="'.$fLoginURL.'" style="margin:5px 10px;"><b>Sign up with Facebook</b></a>
</div>
';
}
和config-facebook.php
session_start();
include_once 'Facebook/autoload.php';
$fb = new \Facebook\Facebook([
'app_id' => '************',
'app_secret' => '************',
'default_graph_version' => 'v2.10'
]);
$helper = $fb->getRedirectLoginHelper();
try {
if(isset($_SESSION['facebook_access_token']))
{$accessToken = $_SESSION['facebook_access_token'];}
else
{$accessToken = $helper->getAccessToken();}
} catch(FacebookResponseException $e) {
echo 'Facebook API Error: ' . $e->getMessage();
exit;
} catch(FacebookSDKException $e) {
echo 'Facebook SDK Error: ' . $e->getMessage();
exit;
}
和此处的结果
Fatal error: Uncaught Facebook\Exceptions\FacebookSDKException: Cross-site request forgery validation failed. Required param "state" missing from persistent data. in /www/wwwroot/fruitask.com/Facebook/Helpers/FacebookRedirectLoginHelper.php:244 Stack trace: #0 /www/wwwroot/fruitask.com/Facebook/Helpers/FacebookRedirectLoginHelper.php(221): Facebook\Helpers\FacebookRedirectLoginHelper->validateCsrf() #1 /www/wwwroot/fruitask.com/config-facebook.php(20): Facebook\Helpers\FacebookRedirectLoginHelper->getAccessToken() #2 /www/wwwroot/fruitask.com/create-acc.php(162): include_once('/www/wwwroot/fr...') #3 {main} thrown in /www/wwwroot/fruitask.com/Facebook/Helpers/FacebookRedirectLoginHelper.php on line 244
请分享一些想法或任何替代方法,我可以使用 PHP 在我的网站上实现 Facebook 登录。提前致谢
我知道我迟到了,但我遇到了这个错误,而且我认为我的解决方案没有包含在上面的回复中,所以这里是:
可能出现此错误的一个原因是,如果您多次向 Facebook 提交相同的 URL 登录请求。例如,用户可能会不耐烦地多次点击登录按钮,从而触发 URL 的多次提交。就我而言,解决方案是使用 JavaScript 函数拦截第一次点击后的所有点击。
将版本更改为 v2.10 检查您在配置 php 文件中使用的图表
// 调用 Facebook API
好吧,我今天遇到了同样的错误,我从 tutorials point
得到了解决方案
在你的回调文件中,只需添加这一行就可以了
if (isset($_GET['state'])) {
$helper->getPersistentDataHandler()->set('state', $_GET['state']);
}
我最近升级到最新版本的 facebook SDK,我在登录用户时遇到问题。我生成登录 link 很好,但是当 facebook 将用户发送回我的网站时令牌,我收到此错误:
fb sdk错误:跨站请求伪造验证失败。持久数据中缺少必需的参数 "state"。
我试着解决了一些问题。我打印出了会话数据中的所有内容以及 GET 请求中的所有内容。我看到 GET 有一个状态参数,会话数据有一个 FBRLH_state 参数。它们都具有相同的值。那它怎么告诉我参数丢失了?
我已经尝试了一些我在其他问题上看到的建议(即开始会话),但似乎没有任何效果。
如有任何帮助,我们将不胜感激!我正在使用 php-graph-sdk-5.5。我的 facebook 连接文件如下
if(!class_exists('facebook')){
class facebook{
private $db = null;
private $fb = null;
private $token = null;
private $DEV = null;
private $sdk_error = null;
private $api_error = null;
private $verbose = false;
private $graph_user = null;
private $db_helper = null;
private $errors = null;
public function __construct($db,
$fb_id = FB_APP_ID,
$fb_secret = FB_APP_SECRET,
$fb_version = FB_DEFAULT_GRAPH_VERSION){
if($this->verbose) echo '<pre>';
if($this->verbose) echo 'starting construction'.PHP_EOL;
$this->db = $db;
if(!$this->fb){
$this->log[] = 'no connect found. building..'.PHP_EOL;
$this->fb = new Facebook\Facebook(array(
'app_id' => $fb_id,
'app_secret' => $fb_secret,
'default_graph_version' => $fb_version));
if(!$this->fb){
die('facebook initialization failure');
}
$this->log[] = 'finished building new connection'.PHP_EOL;
}
}
public function get_login_url($callback_uri, $permissions = ['email','user_birthday']){
global $_DEV,$_config;
$helper = $this->fb->getRedirectLoginHelper();
$callback_host = ($_DEV ? $_config['dev_domain'] : $_config['live_domain']);
$callback_url = 'https://'.$callback_host.$callback_uri;
return $helper->getLoginUrl($callback_url, $permissions);
}
public function catch_token(){
if($this->token){
$this->log[] = 'already have token.'.PHP_EOL;
return $this->token;
} else if(!$this->fb){
$this->log[] = $this->error[] = 'no facebook connection in catch token()';
}
$this->log[] = 'starting catch token routine.'.PHP_EOL;
//$_SESSION['state']=$_GET['state'];
echo '<pre>' . var_export($_SESSION, true) . '</pre>';
echo '<BR><BR><pre>' . var_export($_GET, true) . '</pre>';
$helper = $this->fb->getRedirectLoginHelper();
$this->token = $helper->getAccessToken();
$this->log[] = 'caught token: '.$this->token;
$string_token = $this->token.PHP_EOL;
//die($string_token);
try {
$helper = $this->fb->getRedirectLoginHelper();
$this->token = $helper->getAccessToken();
$this->log[] = 'caught token: '.$this->token;
$string_token = $this->token.PHP_EOL;
return $this->user_flush();
} catch(Facebook\Exceptions\FacebookResponseException $e) {
// When Graph returns an error
$this->log[] = $this->errors[] = 'fb api error: ' . $e->getMessage();
return null;
} catch(Facebook\Exceptions\FacebookSDKException $e) {
// When validation fails or other local issues
$this->log[] = $this->errors[] = 'fb sdk error: ' . $e->getMessage();
return null;
} catch(Exception $e){
$this->log[] = $this->errors[] = 'unknown error: '.$e->getMessage();
return null;
}
}
public function get_token(){
$this->log[] = 'get token called.'.PHP_EOL;
if($this->token){
$this->log[] = 'token found in object'.PHP_EOL;
//echo '<pre>';
//die(debug_print_backtrace());
return $this->token;
} else {
$this->log[] = $this->errors[] = 'token not found in object.'.PHP_EOL;
return null;
}
}
public function get_user($override = false){
$fields = array(
'first_name',
'last_name',
'email',
'id',
'picture',
'birthday',
'gender',);
$fields = implode(',',$fields);
if($this->graph_user === null){
if($this->fb && $this->get_token()){
try {
// Returns a Facebook\FacebookResponse object
$resp_url = '/me?fields='.$fields.'&debug=all';
$this->log[] = $resp_url;
$response = $this->fb->get($resp_url, $this->get_token());
$this->graph_user = $response->getGraphUser();
return $this->graph_user;
}
catch(Facebook\Exceptions\FacebookResponseException $e) {
// When Graph returns an error
$this->api_error = 'fb api error: ' . $e->getMessage();
$this->errors[] = $this->api_error;
return null;
}
catch(Facebook\Exceptions\FacebookSDKException $e) {
// When validation fails or other local issues
$this->sdk_error = 'fb sdk error: ' . $e->getMessage();
$this->errors[] = $this->sdk_error;
return null;
}
} else {
$this->sdk_error = "get_user(): fb connection or token not set. are you logged in?";
$this->errors[] = $this->sdk_error;
//echo '<pre>';
//debug_print_backtrace();
//die('token: '.$this->token);
return null;
}
} else {
$this->sdk_error = "get_user(): graph_user already set";
$this->errors[] = $this->sdk_error;
return $this->graph_user;
}
}
public function get_user_first_name(){
return $this->get_user()['first_name'];
}
public function get_user_last_name(){
return $this->get_user()['last_name'];
}
public function get_user_id(){
return $this->get_user()['id'];
}
public function get_user_email(){
return $this->get_user()['email'];
}
public function get_user_picture(){
return $this->get_user()['picture']['url'];
}
public function get_user_birthday(){
return $this->get_user()['birthday'];
}
public function user_flush(){
//this is the command function.
// runs the basic functionality of this class
// by adding this user to the database if they're not there
// and logging them in if they are.
$this->graph_user = $this->get_user();
//$this->log['graph_user_at_user_flush'] = $this->graph_user;
$this->build_user();
$this->log['GRAPH_USER'] = $this->get_user();
$this->log['user_input_array@user_flush'] = $this->user_input;
if($return = $this->user->fb_register()){
//die(print_r(debug_backtrace(),true));
//$this->log['success return'] = '. '.$return;
return $return;
} else {
//die('<pre>'.print_r(debug_backtrace(),true));
$this->log['fb_register_fail'] = array('fb_register() (also login) failed.',$this->user->get_errors());
return null;
}
}
public function build_user(){
$this->user_input['first_name'] = $this->get_user_first_name();
//$this->user_input['last_name'] = $this->get_user_last_name();
$this->user_input['facebook_id'] = $this->get_user_id();
$this->user_input['email'] = $this->get_user_email();
$this->user_input['image_url'] = $this->get_user_picture();
$this->user_input['birthday'] = $this->get_user_birthday();
if($this->verbose)
print_r($this->user_input);
$this->user = new user($this->user_input,$this->db);
}
public function logout(){
unset($_SESSION['fb_id']);
unset($this->token);
unset($this->fb);
}
public function get_errors(){
return array_unique($this->errors);
}
public function get_log(){
return array_unique($this->log);
}
}
}
//finally, create the connection.
if(!isset($fb))
$fb = new facebook($db);
fb sdk error: Cross-site request forgery validation failed. Required param "state" missing from persistent data.
这与您正在执行两次调用 getRedirectLoginHelper 和 $helper->getAccessToken() 的例程有关 - 一次 "on their own",然后在 try-catch 块中再次调用(复制和粘贴错误,或者不幸的调试尝试?)
我现在有点懒得去查看 SDK 源代码,但我认为它在代码交换令牌后故意取消设置会话中的状态参数,作为使整个过程更容易的一部分安全 - 这样当您第二次调用 getAccessToken 时,它就会失败。
这可能有点晚了,但我希望它对其他人有所帮助。
我遇到这个问题有一段时间了,我四处搜索并看到了很多不同的解决方案,其中许多都禁用了 CSRF 检查。所以在我阅读了所有内容之后,这对我有用。
据我了解,当您的重定向 URL 与您在应用程序设置中设置的重定向不匹配时,您会收到此错误,因此我的问题很容易解决,但我也看到有人遇到问题由于他们的 session 没有正常启动,所以我将涵盖这两个问题。
第 1 步:确保您的 session 已在需要时启动。
例如: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 回调代码在配置之外的另一个文件中,那么也在该文件上启动 session。
例如: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 登录应用程序设置中,转到 有效的 OAuth 重定向 URI,您应该在其中添加指向您的 fb-callback 的 url。 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,以及为什么使用 SERVER_NAME?
因为您的有效的 OAuth 重定向 URI 需要与代码中的重定向 url 匹配,如果在您的应用程序设置中您只将 OAuth 重定向设置为 http://example.com/fb-callback.php and set up your $redirectURL as http://example.com/fb-bacllback.php to make it match but the user entered your site as http://www.example.com 那么用户将收到 Facebook SDK 错误:Cross-site 请求伪造验证失败。持久数据 中缺少必需的参数“state”,因为 URL 用户所在的位置与您的设置不完全匹配。为什么?我不知道。
我的方法是这样的,如果用户以 http://example.com or http://www.example.com 的身份进入您的网站,它将始终与您在应用设置中的设置相匹配。为什么?因为 $_SERVER['SERVER_NAME'] 将 return 带或不带 www 的域取决于用户在浏览器中输入 url 的方式。
这是我的发现,这是唯一没有删除 CSRF 检查对我有用的东西,到目前为止,没有任何问题。
希望对您有所帮助。
如果有人仍然遇到这个问题,只需在回调文件的开头添加一个 session_start()
。
点击登录后还是出现这个错误..
SDK Exception: Cross-site request forgery validation failed. Required param "state" missing from persistent data.
我就跟着看之前的话题和上面的评论。并仔细检查 URL 有效的 OAuth 重定向 URI。
这是我所做的。非常感谢您能分享一些想法并纠正我..
创建-acc.php
///FACEBOOK SIGNUP
session_start();
include_once 'config-facebook.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();
}
$redirectURL = "http://".$_SERVER['SERVER_NAME']."/create-acc.php";
$permissions = ['email'];
$fLoginURL = $helper->getLoginUrl($redirectURL, $permissions);
$facebook_button ='
<div style="background-color:white; color:#4b5563; cursor:pointer;" class="inline-flex border-2 py-1.5 px-5 rounded text-lg border-gray-300">
<div style="margin-top:5px;">
<img style="width:25px;" src="./assets/apps/facebook-logo-2019.png"/>
</div>
<a href="'.$fLoginURL.'" style="margin:5px 10px;"><b>Sign up with Facebook</b></a>
</div>
';
配置-facebook.php
include_once 'Facebook/autoload.php';
$fb = new \Facebook\Facebook([
'app_id' => '**************',
'app_secret' => '*************',
'default_graph_version' => 'v2.10'
]);
$helper = $fb->getRedirectLoginHelper();
我真的是这个编程的新手,并且还在学习。所以如果你帮助它真的节省了我的时间并学习提供的 codes.And 如果我试图添加一些回调代码来获取数据,它在我的工作中看起来像这样
create-acc.php 添加回调代码
///FACEBOOK SIGNUP
session_start();
include_once 'config-facebook.php';
if (isset($accessToken))
{
if (!isset($_SESSION['facebook_access_token']))
{
//get short-lived access token
$_SESSION['facebook_access_token'] = (string) $accessToken;
//OAuth 2.0 client handler
$oAuth2Client = $fb->getOAuth2Client();
//Exchanges a short-lived access token for a long-lived one
$longLivedAccessToken = $oAuth2Client->getLongLivedAccessToken($_SESSION['facebook_access_token']);
$_SESSION['facebook_access_token'] = (string) $longLivedAccessToken;
//setting default access token to be used in script
$fb->setDefaultAccessToken($_SESSION['facebook_access_token']);
}
else
{
$fb->setDefaultAccessToken($_SESSION['facebook_access_token']);
}
if (isset($_GET['code']))
{
header('Location: ./');
}
try {
$fb_response = $fb->get('/me?fields=name,first_name,last_name,email');
$fb_response_picture = $fb->get('/me/picture?redirect=false&height=200');
$fb_user = $fb_response->getGraphUser();
$picture = $fb_response_picture->getGraphUser();
$_SESSION['fb_user_id'] = $fb_user->getProperty('id');
$_SESSION['fb_user_name'] = $fb_user->getProperty('name');
$_SESSION['fb_user_email'] = $fb_user->getProperty('email');
$_SESSION['fb_user_pic'] = $picture['url'];
} catch(Facebook\Exceptions\FacebookResponseException $e) {
echo 'Facebook API Error: ' . $e->getMessage();
session_destroy();
header("Location: ./");
exit;
} catch(Facebook\Exceptions\FacebookSDKException $e) {
echo 'Facebook SDK Error: ' . $e->getMessage();
exit;
}
}
else
{
$redirectURL = "http://".$_SERVER['SERVER_NAME']."/create-acc.php";
$permissions = ['email'];
$fLoginURL = $helper->getLoginUrl($redirectURL, $permissions);
$facebook_button ='
<div style="background-color:white; color:#4b5563; cursor:pointer;" class="inline-flex border-2 py-1.5 px-5 rounded text-lg border-gray-300">
<div style="margin-top:5px;">
<img style="width:25px;" src="./assets/apps/facebook-logo-2019.png"/>
</div>
<a href="'.$fLoginURL.'" style="margin:5px 10px;"><b>Sign up with Facebook</b></a>
</div>
';
}
和config-facebook.php
session_start();
include_once 'Facebook/autoload.php';
$fb = new \Facebook\Facebook([
'app_id' => '************',
'app_secret' => '************',
'default_graph_version' => 'v2.10'
]);
$helper = $fb->getRedirectLoginHelper();
try {
if(isset($_SESSION['facebook_access_token']))
{$accessToken = $_SESSION['facebook_access_token'];}
else
{$accessToken = $helper->getAccessToken();}
} catch(FacebookResponseException $e) {
echo 'Facebook API Error: ' . $e->getMessage();
exit;
} catch(FacebookSDKException $e) {
echo 'Facebook SDK Error: ' . $e->getMessage();
exit;
}
和此处的结果
Fatal error: Uncaught Facebook\Exceptions\FacebookSDKException: Cross-site request forgery validation failed. Required param "state" missing from persistent data. in /www/wwwroot/fruitask.com/Facebook/Helpers/FacebookRedirectLoginHelper.php:244 Stack trace: #0 /www/wwwroot/fruitask.com/Facebook/Helpers/FacebookRedirectLoginHelper.php(221): Facebook\Helpers\FacebookRedirectLoginHelper->validateCsrf() #1 /www/wwwroot/fruitask.com/config-facebook.php(20): Facebook\Helpers\FacebookRedirectLoginHelper->getAccessToken() #2 /www/wwwroot/fruitask.com/create-acc.php(162): include_once('/www/wwwroot/fr...') #3 {main} thrown in /www/wwwroot/fruitask.com/Facebook/Helpers/FacebookRedirectLoginHelper.php on line 244
请分享一些想法或任何替代方法,我可以使用 PHP 在我的网站上实现 Facebook 登录。提前致谢
我知道我迟到了,但我遇到了这个错误,而且我认为我的解决方案没有包含在上面的回复中,所以这里是:
可能出现此错误的一个原因是,如果您多次向 Facebook 提交相同的 URL 登录请求。例如,用户可能会不耐烦地多次点击登录按钮,从而触发 URL 的多次提交。就我而言,解决方案是使用 JavaScript 函数拦截第一次点击后的所有点击。
将版本更改为 v2.10 检查您在配置 php 文件中使用的图表 // 调用 Facebook API
好吧,我今天遇到了同样的错误,我从 tutorials point
得到了解决方案在你的回调文件中,只需添加这一行就可以了
if (isset($_GET['state'])) {
$helper->getPersistentDataHandler()->set('state', $_GET['state']);
}