我试图获得Facebook用户id使用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的感谢任何帮助提前。
我发现只要在生成登录url之前启用PHP会话,并且在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()方法之前,需要确保启用了会话。这通常在大多数web框架中自动完成,但如果你不使用web框架,你可以添加session_start();放到login。php &login-callback.php脚本。您可以覆盖默认的会话处理-参见下面的扩展点。
我添加这个说明,因为它是重要的要记住,如果你碰巧正在运行自己的会话管理或如果你正在运行多个web服务器并行。在这些情况下,依赖php的默认会话方法并不总是有效。
将此代码插入$helper = $fb->getRedirectLoginHelper();
$_SESSION['FBRLH_state']=$_GET['state'];
已经提到了很多很棒的答案,这里是对我有帮助的一个,
我发现问题是跨站点请求伪造验证失败。所需参数"状态"缺失在FB代码,这是解决方案
这行之后
$helper = $fb->getRedirectLoginHelper();
添加以下代码,
if (isset($_GET['state'])) {
$helper->getPersistentDataHandler()->set('state', $_GET['state']);
}
我在Symfony2中使用Facebook SDK时得到了这个错误,编写了一个Twig扩展来显示模板中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扩展中调用的,因为内存处理程序在正常控制器/服务中专门使用SDK时确实可以工作。
显然,状态是在您调用getLoginUrl()
时设置的,并且在您调用getAccessToken()
时检索。如果保存的状态返回null
(因为您的数据处理程序没有达到应有的持久性),则CSRF验证检查失败。
如果你需要以一种特殊的方式处理会话,或者你想在其他地方存储状态,你也可以用'persistent_data_handler' => new MyPersistentDataHandler()
编写你自己的处理程序,使用FacebookSessionPersistentDataHandler作为一个例子。
当Facebook库无法将它从Facebook接收到的状态参数与它在会话中默认设置的状态参数匹配时,就会发生这种情况。如果你正在使用一个框架,如Laravel, Yii2,或Kohana实现自己的会话存储,标准的Facebook会话实现可能无法工作。
要解决这个问题,你需要使用框架的会话库创建自己的PersistentDataInterface
实现,并将其传递给Facebook'Facebook
构造函数。
下面是一个来自Facebook的Laravel持久化处理程序的例子:
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
最后,查看FB代码,我发现问题
跨站点请求伪造验证失败。缺少必需参数" state "
和类似的是由PHP变量$_SESSION['FBRLH_state']
引起的,当FB调用登录回调文件时,由于一些"奇怪"的原因。
为了解决这个问题,我将这个变量"FBRLH_state"
存储在函数$helper->getLoginUrl(...)
调用之后。这是非常重要的,因为只有在调用这个函数之后,当变量$_SESSION['FBRLH_state']
被填充时,它在这个函数中。
$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
类之前添加了session_start();
。
Facebook对象有一个名为persistentDataHandler
的实例变量,通常是FacebookSessionPersistentDataHandler
的一个实例,它有一个set和一个get方法来访问本地PHP会话。
生成回调url时使用:
$loginUrl = $helper->getLoginUrl($callback_url, $permissions);
方法FacebookRedirectLoginHelper->getLoginUrl()
将创建一个32个字符的随机字符串,将其添加到$loginUrl
中,并使用persistentDataHandler
的set方法将其保存到下面的代码中。
$_SESSION['FBRLH_' . 'state']
以后当调用$helper->getAccessToken();
时,url中的状态参数将与存储在同一会话中的状态参数进行比较,以防止CSRF。如果不匹配,则抛出异常。
FacebookSDKException
:跨站请求伪造验证失败。缺少必需参数"state"。
说了这么多,您需要确保在此过程中正确设置了本机PHP会话特性。您可以通过添加
进行检查。die($_SESSION['FBRLH_' . 'state']);
后$loginUrl = $helper->getLoginUrl($callback_url, $permissions);
和
之前$accessToken = $helper->getAccessToken();
查看那个32个字符的字符串是否在那里。
希望有帮助!
对于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()
]);
我在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);
这可能有点晚了,但我希望它能帮助别人,因为这个问题仍然存在。
我有这个问题一段时间了,我已经搜索了周围,看到了很多不同的解决方案,其中许多禁用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登录应用程序设置中,转到Valid OAuth redirect uri ,您应该在其中添加指向fb-callback.php文件的url。
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,并设置你的$redirectURL为http://example.com/fb-bacllback.php,使其匹配,但用户输入你的网站为http://www.example.com,那么用户将得到Facebook SDK错误:跨站请求伪造验证失败。持久性数据中缺少必需的参数"state",因为用户所在的URL与您设置的不完全匹配。为什么?我完全不知道。
我的方法使得它,如果用户输入您的网站为http://example.com或http://www.example.com,它将始终匹配你在你的应用程序设置设置。为什么?因为$_SERVER['SERVER_NAME']将返回带或不带www的域名,这取决于用户在浏览器中输入url的方式。
这是我的发现,这是唯一对我有用的东西,没有删除CSRF检查,到目前为止,没有问题。
我希望这对你有帮助。
你可以这样做用新的状态设置会话
<?php
if(isset($_GET['state'])) {
if($_SESSION['FBRLH_' . 'state']) {
$_SESSION['FBRLH_' . 'state'] = $_GET['state'];
}
}
?>
在我的情况下,我检查了错误,发现错误,导致我执行代码解决方案:
date_default_timezone_set('Europe/Istanbul');
前脚本。效果很好。对于您的位置检查:timezones.europe.php
对我来说很容易修复。我改变了:
$loginUrl = $helper->getLoginUrl('http://www.MYWEBSITE.ca/index_callback.php', $permissions);
:
$loginUrl = $helper->getLoginUrl('http://MYWEBSITE.ca/index_callback.php', $permissions);
删除'www'
解决了这个问题。
如果源主机名与目标主机名不同,则触发错误[如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中面临的一个常见问题。这只是一个SESSION问题。要解决这个问题,可以添加一些代码,如。
在回调脚本通常fb-callback.php添加"session_start();"就在你包含facebook自动加载文件之前。然后在"$helper =$ fb->getRedirectLoginHelper();"行之后输入"$_SESSION['FBRLH_state']=$_GET['state'];"。
示例:
<?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中试图从重定向登录Helper提取access_token。所以使用
getJavaScriptHelper();
不是getRedirectLoginHelper();
间歇性问题解决方案
我是a)重定向到Facebook登录链接,b)从login.php重定向到main.php。用户将转到main.php和其他一些页面,然后在浏览器中单击返回。
最终,他们会点击login.php,并发布一堆信用,但Facebook在一次成功后删除了$_SESSION['FBRLH_state'],所以即使它有正确的$_GET['state'],它也会出错。
解决方案是a)内部跟踪用户是否登录并避免在login.php中重复Facebook逻辑,或者b)跟踪所有最近有效的状态参数,这些参数是由Facebook设置的特定用户(可能在会话中),如果$_GET['state']在该数组中,然后这样做:
$_SESSION['FBRLH_state'] = $_GET['state'];在这种情况下,您可以安全地执行此操作,而不会破坏CSRF保护。
For me设置会话状态有效
完整的代码(在重定向url php)
$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();
}
我正在玩Symfony,并有这个问题一次尝试是,下一个没有。我通过将facebookRedirectLoginHelper对象存储到会话中,并稍后从会话中检索它来解决这个问题,而不是再次向Facebook对象请求它。
文档(撰写本文时Symfony 4.3)声明如下:
在使用session类之前,请确保PHP会话尚未启动。如果您有一个启动会话的遗留会话系统,请参阅遗留会话。
Symfony会话被设计用来替换几个本地PHP函数。应用程序应避免使用session_start()、session_regenerate_id()、session_id()、session_name()和session_destroy(),而应使用下一节中的api。
虽然建议显式地启动会话,但会话实际上是根据需要启动的,也就是说,如果有任何会话请求来读取/写入会话数据。
所以我认为从会话中检索对象本身就会启动php会话
如果你正在使用php框架,请记住这一点。
对我来说,问题是不同的;(我太傻了)我有一个弹出窗口与Facebook登录和再次Facebook登录按钮在登录/注册页面。
- 每当我从其他页面点击弹出的Facebook按钮时,它工作得很好。
- 但是,当我点击Facebook按钮弹出从登录/注册页面,它不会工作。
原因是我重新实例化了Facebook和getRedirectLoginHelper对象。我不得不在登录/注册页面中注释掉这些语句,因为它已经可用了。
$_SESSION['FBRLH_state']=$_GET['state'];
不是正确的方法。尽管它有效。
如果一直看到错误,请清理浏览器缓存。当我使用enbrev解决方案修复了这个问题后,我仍然会遇到这个错误。过了一会儿,我明白了我需要清理缓存,在我重新启动浏览器后,它工作了!