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 协议》,转载必须注明作者和本文链接
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
讨论数量: 1

您好, 我按照您的逻辑写在swoft框架里,总是报错 Bad request,不知道哪里有问题, 我安装了guzzle 5.3, Facebook-sdk-v5.7. 求大神指教~~~

5年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!