Facebook 网页登录基于 Facebook 的 PHP-graph-sdk
第一次使用facebook登录, 也踩了一些坑,写篇文章记录一下吧,避免各位coder少踩一些坑
本篇文章是基于laravel5.5写的,如果用其他框架,可以自己参考着修改
注册了一个企业facebook的账号,申请一个应用,根据要求填写信息即可
facebook应用创建地址:"https://developers.facebook.com/apps/"
应用要求:
1.服务器需要在境外或者服务器能翻墙
2.网站需要是https
如果大家是用laravel或者一些新的框架的话,可以直接使用composer下载php-sdk包
composer require facebook/graph-sdk
github地址是:"https://github.com/facebook/php-graph-sdk"
配置facebook应用信息:
例如我的代码:
在config目录下有一个site.php的配置文件,在文件中加上facebook配置
'facebook' => [
'app_id' => '2176*****64007',
'app_secret' => '2ec436b*******2f1046a73d72150',
'default_graph_version' => 'v2.10'
]
在loginController控制器下增加两个方法
//facebook_login和facebook_callback
增加两个路由
Route::get('facebook/login','LoginController@facebook_login')->name('facebook.login');
Route::match(['get','post'],'facebook/callback','LoginController@facebook_callback')->name('facebook.callback');
facebook_login方法
/**
* facebook 登录
* @param Request $request
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function facebook_login(Request $request)
{
session_start();//启用session,防止facebook报错
$facebookConfig = config('site.facebook');
$fb = new Facebook($facebookConfig);
$helper = $fb->getRedirectLoginHelper();
$permissions = ['email']; // Optional permissions
$facebookRedirectUrl = route('home.facebook.callback');//facebook的回调方法,参考第二个路由,千万不要直接copy我的代码
$facebookLoginUrl = $helper->getLoginUrl($facebookRedirectUrl,$permissions);
return redirect($facebookLoginUrl);
}
facebook_callback方法内容
/**
* facebook 登录回调
* @param Request $request
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
* @throws \Facebook\Exceptions\FacebookSDKException
*/
public function facebook_callback(Request $request)
{
session_start();//启用session,防止facebook报错,不启用session会报错,可以自行尝试,不会最好了
if($request->get('error') == 'access_denied'){
return redirect('/');
}
$facebookConfig = config('site.facebook');
//注意这里的坑,有很多人的guzzle版本都是6.*的,现在的facebook的sdk只能支持guzzle5.*,请检查你的版本
$facebookConfig['http_client_handler'] = 'guzzle';//如果是5.*,加上这句话就可以了
//如果是guzzle6.*,解决方法有两个,一是降低guzzle的版本,然后使用上面那句话,二是重写请求
//请求重写的参考,Guzzle6HttpClient这个类写在下面
/**
$client = new GuzzleHttp\Client;
$facebookConfig['http_client_handler'] = new Guzzle6HttpClient($client);
**/
$fb = new Facebook($facebookConfig);
$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
$message = 'Graph returned an error: ' . $e->getMessage();
Log::warning('facebook login failed',['error'=>$message]);//Log的命名空间没加,写的时候自己加一下
return back()->withErrors([$message]);
} catch(Facebook\Exceptions\FacebookSDKException $e) {
// When validation fails or other local issues
$message = 'Facebook SDK returned an error: ' . $e->getMessage();
Log::warning('facebook login failed',['error'=>$message]);
return back()->withErrors([$message]);
}
if (! isset($accessToken)) {
if ($helper->getError()) {
$message = "Error: " . $helper->getError() . "\n";
$message .= "Error Code: " . $helper->getErrorCode() . "\n";
$message .= "Error Reason: " . $helper->getErrorReason() . "\n";
$message .= "Error Description: " . $helper->getErrorDescription() . "\n";
} else {
$message = 'Bad request';
}
Log::warning('facebook login failed',['error'=>$message]);
return abort(401);
}
$oAuth2Client = $fb->getOAuth2Client();
$tokenMetadata = $oAuth2Client->debugToken($accessToken);
$tokenMetadata->validateAppId(config('site.facebook.app_id'));
$tokenMetadata->validateExpiration();
if (! $accessToken->isLongLived()) {
try {
$accessToken = $oAuth2Client->getLongLivedAccessToken($accessToken);
} catch (Facebook\Exceptions\FacebookSDKException $e) {
$message = 'Error getting long-lived access token'. $e->getMessage();
Log::warning('facebook login failed',['error'=>$message]);
return back()->withErrors([$message]);
}
}
$_SESSION['fb_access_token'] = (string) $accessToken;
$fb->setDefaultAccessToken($accessToken);
$response = $fb->get('/me?locale=en_US&fields=id,name,email');
$userNode = $response->getGraphUser();
$email = $userNode->getField('email');
$name = $userNode->getField('name');
$fb_user_id = $userNode->getField('id');
//拿到这些内容之后,再根据自己的逻辑进行处理
}
Guzzle6HttpClient类的重写参考
在vendor->facebook->graph-sdk->src->Facebook->HttpClients目录写新增一个类Guzzle6HttpClient
内容如下:
namespace Facebook\HttpClients;
use Facebook\Exceptions\FacebookSDKException;
use Facebook\Http\GraphRawResponse;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Psr7\Request;
class Guzzle6HttpClient implements FacebookHttpClientInterface
{
private $client;
public function __construct(Client $client)
{
$this->client = $client;
}
public function send($url, $method, $body, array $headers, $timeOut)
{
$request = new Request($method, $url, $headers, $body);
try {
$response = $this->client->send($request, ['timeout' => 60, 'http_errors' => false]);
} catch (RequestException $e) {
throw new FacebookSDKException($e->getMessage(), $e->getCode());
}
$httpStatusCode = $response->getStatusCode();
$responseHeaders = $response->getHeaders();
foreach ($responseHeaders as $key => $values) {
$responseHeaders[$key] = implode(', ', $values);
}
$responseBody = $response->getBody()->getContents();
return new GraphRawResponse($responseHeaders, $responseBody, $httpStatusCode);
}
}
搞完这些还需要在应用里面修改配置,把facebook_callback的回调链接填写在应用配置有效 OAuth 跳转 URI下
最后测试一下是否能拿到facebook的用户信息
如果拿到了恭喜你很顺利,要是没有,再根据错误信息进行修正吧
本作品采用《CC 协议》,转载必须注明作者和本文链接
您好, 我按照您的逻辑写在swoft框架里,总是报错 Bad request,不知道哪里有问题, 我安装了guzzle 5.3, Facebook-sdk-v5.7. 求大神指教~~~