第一次使用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 協議》,轉載必須註明作者和本文連結