【问题标题】:How to integrate Facebook PHP SDK with Laravel 5.4?如何将 Facebook PHP SDK 与 Laravel 5.4 集成?
【发布时间】:2017-08-14 05:02:27
【问题描述】:

我正在寻找一种将 Facebook PHP SDK 与 Laravel 5.4 集成的简单方法。本质上,我想在我的 Laravel 应用程序中将其作为服务提供。 github上当然有SammyK/LaravelFacebookSdk。但由于某种原因,我不想使用它。我觉得这个设置增加了另一个我必须理解的层,并在约束范围内工作。

还有 Laravel 自己的 Socialite 包。但这本质上只是为了简单的身份验证。如果我想上传照片、cmets、批量请求,这些都是不可能的。 Socialite 不使用 Facebook 的 PHP SDK 作为依赖项。它使用 Guzzle 包直接发出 API 请求以进行身份​​验证。

由于没有简单的 SO 解决方案以最少的步骤直接集成 Facebook SDK,所以我想我会写这个。

【问题讨论】:

  • 对于社交媒体登录相关的 laravel 最佳插件可用的东西 'laravel/socialite' 也显示在 laravel 官方文档 url 中:laravel.com/docs/5.0/authentication#social-authentication
  • 一年前,我创建了一个简单的包,它只是将 Facebook 类实例绑定到服务容器,允许您在 .env 文件中注册您的密钥并以“laravel 方式”进行操作。但是,这是未经测试的代码,是在 Laravel 5.3(我认为)上开发的,一年前...如果您有兴趣,可以查看代码:github.com/ElMatella/SimpleFacebookLaravelSdk 它也可以在 packagist/composer 上找到

标签: laravel facebook-php-sdk laravel-5.4


【解决方案1】:

首先,编辑项目根文件夹中的 composer.json 以包含 Facebook SDK:

{
  "require" : {
    "facebook/graph-sdk" : "~5.0"
  }
}

接下来在 shell 提示符下运行 composer update 以将 sdk 拉入供应商文件夹。

现在我们想在我们的应用中使用 Facebook SDK 作为服务提供商。但在此之前,让我们设置我们的app_idapp_secretdefault_graph_version,它们是向 Facebook API 发出请求时所需的参数。 app_id和app_secret可以通过Facebook Developers网站注册获取。

一旦我们从 Facebook 获得这些凭据,我们现在将编辑项目根文件夹中的 .env 文件。将它们添加到末尾:

FACEBOOK_APP_ID=xxxxxxxxxxxxxxxx
FACEBOOK_APP_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
FACEBOOK_DEFAULT_GRAPH_VERSION=v2.8

将 xxx.. 替换为提供给您的值。请注意,变量名称只是我自己的创造。您可以随意命名它们。我们现在必须使用这些变量来设置一个单独的配置文件。我们需要这样做,以便我们可以使用 Laravel 的 config() 辅助函数在应用程序中的任何位置检索值。因此,让我们在 config 文件夹中创建 facebook.php 并添加以下内容:

<?php

return [
    'config' => [
        'app_id' => env('FACEBOOK_APP_ID', null),
        'app_secret' => env('FACEBOOK_APP_SECRET', null),
        'default_graph_version' => env('FACEBOOK_DEFAULT_GRAPH_VERSION', 'v2.8'),
    ],
];

通过这个简单的设置,我们现在可以从应用程序的任何位置调用config('facebook.config')。它将返回数组以及从 .env 文件匹配的相关值。

现在让我们将其设置为服务提供者,这样我们就不必在每次调用 Facebook API 时检索这些凭据并构建新的 Facebook 对象。

在 Laravel 5.4 中,打开文件 app\Providers\AppServiceProvider.php。如果您没有此文件或想单独制作一个,则可以在 shell 中创建一个新的服务提供者:

php artisan make:provider FacebookServiceProvider

我们现在可以在 Providers 文件夹中编辑FacebookServiceProvider.php。唯一的区别是我们需要在config/app.php 文件中注册它。您可以在 $providers 数组的末尾添加以下内容:

App\Providers\FacebookServiceProvider::class,

要继续相关代码,在AppServiceProvider.php 或我们的新FacebookServiceProvider.php 中,我们首先在顶部包含:use Facebook\Facebook;。然后在register() method 中添加以下内容:

$this->app->singleton(Facebook::class, function ($app) {
            return new Facebook(config('facebook.config'));
        });

您可能会注意到我将类绑定为singleton,因为对于我的应用程序,我想重用服务容器中的相同对象。 Laravel 提供了 other types of bindings,你可能想看看。

整个代码如下所示(我使用的是 AppServiceProvider.php):

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Facebook\Facebook;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }

    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        $this->app->singleton(Facebook::class, function ($app) {
            return new Facebook(config('facebook.config'));
        });
    }
}

就是这样。我们现在将 Facebook 作为应用程序的服务提供。我们现在可以inject facebook 对象在我们想在我们的应用程序中使用它的任何地方。从这里开始,您可以简单地按照Facebook documentation 的说明调用他们的 API。'

Extra Stuff,仅作为示例:

在继续之前,我想提一下,我发现 Symfony 的人写的系列文章对理解 Service ContainerDependency Injection 的概念很有帮助。你可以find them here

现在让我们尝试执行一个基本操作,例如从 facebook 检索一个人的姓名。为了获取有关 facebook 用户的信息,我们需要通过发送基本参数来调用 Facebook API:用户的 facebook id 以及访问令牌。我们分别称它们为uidaccess_token。您需要使用 Facebook 的一种方法来检索这些:

  1. FacebookRedirectLoginHelper - 当您希望从服务器端进行 Facebook 身份验证时。
  2. FacebookCanvasHelper - 用于基于客户端画布的应用身份验证
  3. FacebookJavaScriptHelper - 用于客户端 javascript 身份验证

您可以按照 Facebook 的 getting started 指南中提供的步骤设置所需的身份验证类型。

我的应用程序非常简单,因此我使用了客户端 javascript 身份验证。我也同时使用 jquery。由于我使用 Laravel 的刀片引擎,因此我的 javascript 直接嵌入到视图文件中,这样我就可以包含 Laravel 的 csrf_token() 并使用其他帮助函数,例如 url()。客户端 javascript 如下所示。请记住将appId 替换为您的值并将文件另存为login.blade.php

<html>
<head>
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<button id="btn-login" type="button" class="btn btn-primary btn-lg">
    <span> Login with Facebook</span>
</button>

<script>
$(document).ready(function() {
    $.ajaxSetup({ cache: true }); // since I am using jquery as well in my app
    $.getScript('//connect.facebook.net/en_US/sdk.js', function () {
        // initialize facebook sdk
        FB.init({
            appId: 'xxxxxxxxxxxxxxxx', // replace this with your id
            status: true,
            cookie: true,
            version: 'v2.8'
        });

        // attach login click event handler
        $("#btn-login").click(function(){
            FB.login(processLoginClick, {scope:'public_profile,email,user_friends', return_scopes: true});  
        });
    });

// function to send uid and access_token back to server
// actual permissions granted by user are also included just as an addition
function processLoginClick (response) {    
    var uid = response.authResponse.userID;
    var access_token = response.authResponse.accessToken;
    var permissions = response.authResponse.grantedScopes;
    var data = { uid:uid, 
                 access_token:access_token, 
                 _token:'{{ csrf_token() }}', // this is important for Laravel to receive the data
                 permissions:permissions 
               };        
    postData("{{ url('/login') }}", data, "post");
}

// function to post any data to server
function postData(url, data, method) 
{
    method = method || "post";
    var form = document.createElement("form");
    form.setAttribute("method", method);
    form.setAttribute("action", url);
    for(var key in data) {
        if(data.hasOwnProperty(key)) 
        {
            var hiddenField = document.createElement("input");
            hiddenField.setAttribute("type", "hidden");
            hiddenField.setAttribute("name", key);
            hiddenField.setAttribute("value", data[key]);
            form.appendChild(hiddenField);
         }
    }
    document.body.appendChild(form);
    form.submit();
}

</script>
</body>
</html>

如果您的应用需要用户提供不同的权限集,请编辑 scope 字段。对于所有可用的 Facebook 权限see here

所以基本上,我的代码有一个登录按钮,当用户单击它时,javascript sdk 会启动并弹出一个登录窗口。用户登录后,我会将数据发布回服务器,就像发布表单一样。

现在回到服务器端,因为我们有uidaccess_token,我们可以将它们存储到数据库中,然后从我们的服务器对 Facebook API 进行简单调用。在routes/web.php设置路由接收表单数据:

Route::post('login', 'FacebookUser@store');

在 shell 中制作FacebookUser 控制器:

php artisan make:controller FacebookUser

而控制器的代码如下:

<?php

namespace App\Http\Controllers;

use Request;
use App\User; // you need to define the model appropriately
use Facebook\Facebook;

class FacebookUser extends Controller
{
    public function store(Facebook $fb) //method injection
    {
        // retrieve form input parameters
        $uid = Request::input('uid');
        $access_token = Request::input('access_token');
        $permissions = Request::input('permissions');

        // assuming we have a User model already set up for our database
        // and assuming facebook_id field to exist in users table in database
        $user = User::firstOrCreate(['facebook_id' => $uid]); 

        // get long term access token for future use
        $oAuth2Client = $fb->getOAuth2Client();

        // assuming access_token field to exist in users table in database
        $user->access_token = $oAuth2Client->getLongLivedAccessToken($access_token)->getValue();
        $user->save();

        // set default access token for all future requests to Facebook API            
        $fb->setDefaultAccessToken($user->access_token);

        // call api to retrieve person's public_profile details
        $fields = "id,cover,name,first_name,last_name,age_range,link,gender,locale,picture,timezone,updated_time,verified";
        $fb_user = $fb->get('/me?fields='.$fields)->getGraphUser();
        dump($fb_user);
    }    
}

请注意,通过使用setDefaultAccessToken(),可以在应用程序代码库后续处理的任何部分从服务容器中检索 $fb 对象。 $fb 可直接用于发出 Facebook API 请求。在当前请求-响应生命周期内,无需再次使用 app_id、app_secret 构建 $fb,也无需为当前用户再次设置访问令牌。这是因为 $fb 是单例的,因此在当前请求-响应生命周期中,当 Facebook 服务调用服务容器时,返回的是相同的对象。

如果您无法进行方法注入来获取 $fb 对象,则有other ways of resolving it。我个人最喜欢的是使用 resolve() 帮助器,因为它的工作原理与类中的对象上下文或静态函数无关。

$fb = resolve('Facebook\Facebook');

【讨论】:

  • 这个答案被低估了
  • $token 未定义
  • @HashanKanchana,感谢您指出这一点。那应该是 $access_token,我现在改了
  • 我们可以在本地服务器上运行它吗?
  • @ZainFarooq,是的,只要有互联网连接调用 facebook api,您就可以在本地运行它。其实上面的代码是在本地测试过的。
猜你喜欢
  • 2017-09-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-04
  • 1970-01-01
  • 1970-01-01
  • 2012-04-09
  • 1970-01-01
相关资源
最近更新 更多