ahmedzidan/laravel-facebook-sdk

为 Laravel & Lumen 5.x 完全单元测试的 Facebook SDK v5 集成

3.4.3 2019-12-16 12:52 UTC

README

Build Status Latest Stable Version Total Downloads License

一个完全单元测试的包,用于轻松地将 Facebook SDK v5 集成到 Laravel 和 Lumen 5.0、5.1、5.2 和 5.3。

这是一个针对 Laravel 和 Lumen 5.0、5.1、5.2 和 5.3 的包

Laravel 5

Lumen 5

我是否应该只使用 Laravel Socialite?

Laravel 5 支持使用 Socialite 进行社交认证,允许您使用 OAuth 2.0 提供商进行认证。Facebook 登录使用 OAuth 2.0,因此 Socialite 支持 Facebook 登录。

如果您只需要认证应用程序并获取用户访问令牌以拉取用户的基本数据,那么 Socialite 或 The PHP League 的 Facebook OAuth Client 应该能满足您的需求。

但是,如果您需要以下任何功能,则希望将 Facebook PHP SDK 与此包结合使用

安装

将 Laravel Facebook SDK 包添加到您的 composer.json 文件中。

{
    "require": {
        "sammyk/laravel-facebook-sdk": "^3.0"
    }
}

服务提供者

在您的应用程序配置中,将 LaravelFacebookSdkServiceProvider 添加到提供者数组中。

'providers' => [
    SammyK\LaravelFacebookSdk\LaravelFacebookSdkServiceProvider::class,
    ];

Lumen,请将提供者添加到您的 bootstrap/app.php 文件中。

$app->register(SammyK\LaravelFacebookSdk\LaravelFacebookSdkServiceProvider::class);

门面(可选)

如果您想使用门面,请将其添加到应用程序配置中的别名数组中。

'aliases' => [
    'Facebook' => SammyK\LaravelFacebookSdk\FacebookFacade::class,
    ];

但是,有 更好的方式 来使用此包,那就是 不使用门面

IoC 容器

IoC 容器将自动为您解决 LaravelFacebookSdk 依赖项。您可以通过多种方式从 IoC 容器中获取 LaravelFacebookSdk 的实例。

// Directly from the IoC
$fb = App::make('SammyK\LaravelFacebookSdk\LaravelFacebookSdk');
// Or in PHP >= 5.5
$fb = app(SammyK\LaravelFacebookSdk\LaravelFacebookSdk::class);

// From a constructor
class FooClass {
    public function __construct(SammyK\LaravelFacebookSdk\LaravelFacebookSdk $fb) {
       // . . .
    }
}

// From a method
class BarClass {
    public function barMethod(SammyK\LaravelFacebookSdk\LaravelFacebookSdk $fb) {
       // . . .
    }
}

// Or even a closure
Route::get('/facebook/login', function(SammyK\LaravelFacebookSdk\LaravelFacebookSdk $fb) {
    // . . .
});

配置文件

在 Facebook 中创建应用程序后,您需要提供应用程序 ID 和密钥。在 Laravel 中,您可以使用 artisan 命令发布配置文件。

$ php artisan vendor:publish --provider="SammyK\LaravelFacebookSdk\LaravelFacebookSdkServiceProvider" --tag="config"

文件在哪里? Laravel 5 将配置文件发布到 /config/laravel-facebook-sdk.php

Lumen 中,您需要手动将配置文件从 /src/config/laravel-facebook-sdk.php 复制到您基础项目目录中的配置文件夹。Lumen 默认没有 /config 文件夹,所以如果您还没有创建它,则需要创建。

所需配置值

您需要在配置文件中更新 app_idapp_secret 值,使用 您的应用程序 ID 和密钥

默认情况下,配置文件将查找环境变量以获取您的应用程序 ID 和密钥。建议您使用环境变量来存储这些信息,以保护您的应用程序密钥免受攻击者侵害。请确保更新您的 /.env 文件以包含应用程序 ID 和密钥。

FACEBOOK_APP_ID=1234567890
FACEBOOK_APP_SECRET=SomeFooAppSecret

用户登录重定向示例

以下是一个使用 重定向方法 登录您应用程序的完整示例。

此示例还演示了如何 将短期访问令牌交换为长期访问令牌 并在用户表中不存在条目时保存用户。

最后,它将使用 Laravel 内置的用户身份验证登录用户。

Lumen 中的会话:“通过重定向登录”功能依赖于会话来存储一个 CSRF 令牌。由于 Lumen 5.2+ 中不存在会话,您需要使用 不同方法 获取访问令牌。为了测试,您可以直接从 Graph API 探索器 中获取访问令牌(请确保从“应用程序”下拉菜单中选择您的应用程序)。

// Generate a login URL
Route::get('/facebook/login', function(SammyK\LaravelFacebookSdk\LaravelFacebookSdk $fb)
{
    // Send an array of permissions to request
    $login_url = $fb->getLoginUrl(['email']);

    // Obviously you'd do this in blade :)
    echo '<a href="' . $login_url . '">Login with Facebook</a>';
});

// Endpoint that is redirected to after an authentication attempt
Route::get('/facebook/callback', function(SammyK\LaravelFacebookSdk\LaravelFacebookSdk $fb)
{
    // Obtain an access token.
    try {
        $token = $fb->getAccessTokenFromRedirect();
    } catch (Facebook\Exceptions\FacebookSDKException $e) {
        dd($e->getMessage());
    }

    // Access token will be null if the user denied the request
    // or if someone just hit this URL outside of the OAuth flow.
    if (! $token) {
        // Get the redirect helper
        $helper = $fb->getRedirectLoginHelper();

        if (! $helper->getError()) {
            abort(403, 'Unauthorized action.');
        }

        // User denied the request
        dd(
            $helper->getError(),
            $helper->getErrorCode(),
            $helper->getErrorReason(),
            $helper->getErrorDescription()
        );
    }

    if (! $token->isLongLived()) {
        // OAuth 2.0 client handler
        $oauth_client = $fb->getOAuth2Client();

        // Extend the access token.
        try {
            $token = $oauth_client->getLongLivedAccessToken($token);
        } catch (Facebook\Exceptions\FacebookSDKException $e) {
            dd($e->getMessage());
        }
    }

    $fb->setDefaultAccessToken($token);

    // Save for later
    Session::put('fb_user_access_token', (string) $token);

    // Get basic info on the user from Facebook.
    try {
        $response = $fb->get('/me?fields=id,name,email');
    } catch (Facebook\Exceptions\FacebookSDKException $e) {
        dd($e->getMessage());
    }

    // Convert the response to a `Facebook/GraphNodes/GraphUser` collection
    $facebook_user = $response->getGraphUser();

    // Create the user if it does not exist or update the existing entry.
    // This will only work if you've added the SyncableGraphNodeTrait to your User model.
    $user = App\User::createOrUpdateGraphNode($facebook_user);

    // Log the user into Laravel
    Auth::login($user);

    return redirect('/')->with('message', 'Successfully logged in with Facebook');
});

有关用户认证方式的更多详细信息,请参阅 Facebook 登录

向 Facebook 发送请求

通过 Graph API 进行 Facebook 请求。此包是官方 Facebook PHP SDK v5 的 Laravel 封装,因此此包中也提供了官方 SDK 所有的方法。

获取用户信息

以下代码段将检索表示登录用户的 用户节点

try {
  $response = $fb->get('/me?fields=id,name,email', 'user-access-token');
} catch(\Facebook\Exceptions\FacebookSDKException $e) {
  dd($e->getMessage());
}

$userNode = $response->getGraphUser();
printf('Hello, %s!', $userNode->getName());

有关 get() 方法的更多信息。

Facebook 登录

当我们说“使用 Facebook 登录”时,我们真正意味着“获取一个用户访问令牌,以便代表用户调用 Graph API”。这是通过 Facebook 通过 OAuth 2.0 实现的。有几种方法可以使用 Facebook PHP SDK 中的“辅助工具”来登录用户。

支持的四种登录方法如下

  1. 通过重定向登录(OAuth 2.0)
  2. 通过 JavaScript 登录(带有 JS SDK Cookie)
  3. 通过应用程序画布登录(带有签名请求)
  4. 通过页面标签登录(带有签名请求)

通过重定向登录

将用户登录到您的应用程序的最常见方法之一是使用重定向 URL。

这个想法是生成一个唯一的URL,用户点击该URL。一旦用户点击链接,就会被重定向到Facebook,要求用户授予您的应用程序请求的任何权限。用户响应后,Facebook将重定向用户回到您指定的回调URL,并带有成功或错误响应。

可以使用SDK的getRedirectLoginHelper()方法获取重定向助手。

生成登录URL

您可以得到一个登录URL,就像使用Facebook PHP SDK v5一样。

Route::get('/facebook/login', function(SammyK\LaravelFacebookSdk\LaravelFacebookSdk $fb) {
    $login_link = $fb
            ->getRedirectLoginHelper()
            ->getLoginUrl('https://exmaple.com/facebook/callback', ['email', 'user_events']);
    
    echo '<a href="' . $login_link . '">Log in with Facebook</a>';
});

但是,如果您在配置文件中设置了default_redirect_uri回调URL,您可以使用getLoginUrl()包装方法,该方法将默认回调URL(default_redirect_uri)和权限范围(default_scope)设置为配置文件中设置的值。

$login_link = $fb->getLoginUrl();

或者,您可以将权限和自定义回调URL传递给包装器以覆盖默认配置。

注意:由于权限列表有时会发生变化,但回调URL通常保持不变,因此权限数组是getLoginUrl()包装方法中的第一个参数,这与SDK的getRedirectLoginHelper()->getLoginUrl($url, $permissions)方法相反。

$login_link = $fb->getLoginUrl(['email', 'user_status'], 'https://exmaple.com/facebook/callback');
// Or, if you want to default to the callback URL set in the config
$login_link = $fb->getLoginUrl(['email', 'user_status']);

从回调URL获取访问令牌

用户点击上面的登录链接并确认或拒绝应用程序权限请求后,将被重定向到指定的回调URL。

在回调URL上获取访问令牌的标准“SDK”方法如下

Route::get('/facebook/callback', function(SammyK\LaravelFacebookSdk\LaravelFacebookSdk $fb) {
    try {
        $token = $fb
            ->getRedirectLoginHelper()
            ->getAccessToken();
    } catch (Facebook\Exceptions\FacebookSDKException $e) {
        // Failed to obtain access token
        dd($e->getMessage());
    }
});

LaravelFacebookSdk中有一个名为getAccessTokenFromRedirect()的包装方法,该方法将回调URL默认设置为laravel-facebook-sdk.default_redirect_uri配置值。

Route::get('/facebook/callback', function(SammyK\LaravelFacebookSdk\LaravelFacebookSdk $fb) {
    try {
        $token = $fb->getAccessTokenFromRedirect();
    } catch (Facebook\Exceptions\FacebookSDKException $e) {
        // Failed to obtain access token
        dd($e->getMessage());
    }
    
    // $token will be null if the user denied the request
    if (! $token) {
        // User denied the request
    }
});

使用JavaScript登录

如果您正在使用JavaScript SDK,您可以从JavaScript SDK设置的cookie中获取访问令牌。

默认情况下,JavaScript SDK不会设置cookie,因此您需要在调用SDK时明确启用它,使用cookie: true

FB.init({
  appId      : 'your-app-id',
  cookie     : true,
  version    : 'v2.9'
});

使用FB.login()使用JavaScript SDK登录用户后,您可以从存储在由JavaScript SDK设置的cookie中的签名请求中获取用户访问令牌。

Route::get('/facebook/javascript', function(SammyK\LaravelFacebookSdk\LaravelFacebookSdk $fb) {
    try {
        $token = $fb->getJavaScriptHelper()->getAccessToken();
    } catch (Facebook\Exceptions\FacebookSDKException $e) {
        // Failed to obtain access token
        dd($e->getMessage());
    }

    // $token will be null if no cookie was set or no OAuth data
    // was found in the cookie's signed request data
    if (! $token) {
        // User hasn't logged in using the JS SDK yet
    }
});

从App Canvas登录

TokenMismatchException:默认的Laravel安装将在尝试在Facebook中查看您的应用程序时抛出TokenMismatchException。请参阅如何解决此问题

如果您的应用程序存在于Facebook应用程序画布的上下文中,您可以从第一次页面加载时通过POST到您的应用程序的签名请求中获取访问令牌。

注意:画布助手仅从Facebook接收到的签名请求数据中获取现有的访问令牌。如果访问您的应用程序的用户尚未授权您的应用程序或访问令牌已过期,则getAccessToken()方法将返回null。在这种情况下,您需要使用重定向JavaScript登录用户。

使用SDK的画布助手从签名请求数据中获取访问令牌。

Route::match(['get', 'post'], '/facebook/canvas', function(SammyK\LaravelFacebookSdk\LaravelFacebookSdk $fb) {
    try {
        $token = $fb->getCanvasHelper()->getAccessToken();
    } catch (Facebook\Exceptions\FacebookSDKException $e) {
        // Failed to obtain access token
        dd($e->getMessage());
    }

    // $token will be null if the user hasn't authenticated your app yet
    if (! $token) {
        // . . .
    }
});

从页面标签登录

TokenMismatchException:默认的Laravel安装将在尝试在Facebook中查看您的页面标签时抛出TokenMismatchException。请参阅如何解决此问题

如果您的应用程序存在于Facebook页面标签的上下文中,这就像应用程序画布一样,并且“从App Canvas登录”方法也可以用来获取访问令牌。但是,页面标签在签名请求中还有额外的数据。

SDK提供了一个页面标签助手,用于在页面标签的上下文中从已签名的请求数据中获取访问令牌。

Route::match(['get', 'post'], '/facebook/page-tab', function(SammyK\LaravelFacebookSdk\LaravelFacebookSdk $fb) {
    try {
        $token = $fb->getPageTabHelper()->getAccessToken();
    } catch (Facebook\Exceptions\FacebookSDKException $e) {
        // Failed to obtain access token
        dd($e->getMessage());
    }

    // $token will be null if the user hasn't authenticated your app yet
    if (! $token) {
        // . . .
    }
});

其他授权请求

Facebook支持两种其他类型的授权URL - 重新请求和重新认证。

重新请求

重新请求(或重新请求?)会再次询问用户之前拒绝的权限。使用重新请求URL而不是仅用正常登录链接进行重定向非常重要,因为

一旦有人拒绝了一项权限,登录对话框将不会再次询问,除非你明确告诉对话框你正在重新请求拒绝的权限。- Facebook 文档

你可以使用 getReRequestUrl() 方法生成重新请求URL。

$rerequest_link = $fb->getReRequestUrl(['email'], 'https://exmaple.com/facebook/login');
// Or, if you want to default to the callback URL set in the config
$rerequest_link = $fb->getReRequestUrl(['email']);

重新认证

重新认证 会强制用户再次输入他们的Facebook账户密码以确认他们的身份。这在你需要在你的Web应用程序中更改或查看敏感数据之前添加另一层安全性时非常有用。

你可以使用 getReAuthenticationUrl() 方法生成重新认证URL。

$re_authentication_link = $fb->getReAuthenticationUrl(['email'], 'https://exmaple.com/facebook/login');
// Or, if you want to default to the callback URL set in the config
$re_authentication_link = $fb->getReAuthenticationUrl(['email']);
// Or without permissions
$re_authentication_link = $fb->getReAuthenticationUrl();

保存访问令牌

在大多数情况下,除非你计划在用户不在浏览你的应用程序时(例如,凌晨3点的CRON作业)代表用户向Graph API发出请求,否则你不需要将访问令牌保存到数据库中。

在你获取访问令牌后,你可以将其存储在会话中,以供后续请求使用。

Session::put('facebook_access_token', (string) $token);

然后在每个调用Graph API的脚本中,你可以从会话中提取令牌并将其设置为默认值。

$token = Session::get('facebook_access_token');
$fb->setDefaultAccessToken($token);

在数据库中保存从Facebook获取的数据

将Graph API接收的数据保存到数据库有时可能是一项繁琐的任务。由于Graph API以可预测的格式返回数据,因此 SyncableGraphNodeTrait 可以使将数据保存到数据库的过程变得轻松。

任何实现了 SyncableGraphNodeTrait 的Eloquent模型都将应用 createOrUpdateGraphNode() 方法。此方法确实使直接从Facebook返回的数据创建或更新本地数据库变得简单。

use SammyK\LaravelFacebookSdk\SyncableGraphNodeTrait;

class Event extends Eloquent {
    use SyncableGraphNodeTrait;
}

例如,如果你有一个名为 Event 的Eloquent模型,以下是你可以如何从Graph API获取特定事件并将其作为新条目插入数据库或用新信息更新现有条目的方法。

$response = $fb->get('/some-event-id?fields=id,name');
$eventNode = $response->getGraphEvent();

// A method called createOrUpdateGraphNode() on the `Event` eloquent model
// will create the event if it does not exist or it will update the existing
// record based on the ID from Facebook.
$event = Event::createOrUpdateGraphNode($eventNode);

createOrUpdateGraphNode() 将自动将返回的字段名称映射到你的数据库中的列名称。例如,如果你的 events 表中的列名称与 事件 节点的字段名称不匹配,你可以 映射字段

字段映射

由于你的数据库中列的名称可能与Graph节点中的字段名称不匹配,因此你可以使用 $graph_node_field_aliases 静态变量映射你的 User 模型中的字段名称。

数组的 keys 是Graph节点上的字段名称。数组的 values 是本地数据库中的列名称。

use SammyK\LaravelFacebookSdk\SyncableGraphNodeTrait;

class User extends Eloquent implements UserInterface
{
    use SyncableGraphNodeTrait;
    
    protected static $graph_node_field_aliases = [
        'id' => 'facebook_user_id',
        'name' => 'full_name',
        'graph_node_field_name' => 'database_column_name',
    ];
}

指定 "可填充" 字段

默认情况下,createOrUpdateGraphNode() 方法会尝试将节点的所有字段插入到数据库中。但有时 Graph API 会返回你未明确请求且不存在于你的数据库中的字段。在这种情况下,我们可以通过 $graph_node_fillable_fields 属性来白名单特定的字段。

use SammyK\LaravelFacebookSdk\SyncableGraphNodeTrait;

class Event extends Eloquent
{
    use SyncableGraphNodeTrait;
    
    protected static $graph_node_fillable_fields = ['id', 'name', 'start_time'];
}

使用数据库列的名称。例如,如果你已经将 id 字段别名到数据库中的 facebook_id 列,你将需要在你的 $graph_node_fillable_fields 数组中指定 facebook_id

嵌套字段映射

由于 Graph API 会将请求中的一些字段作为其他节点/对象返回,你可以使用 Laravel 的 array_dot() 表示法来引用这些字段的值。

一个例子可能是对 /me/events 端点发出请求,遍历所有事件并将它们保存到你的 Event 模型中。事件节点会返回 位置字段 作为 位置节点。响应数据可能如下所示

{
  "data": [
    {
      "id": "123", 
      "name": "Foo Event", 
      "place": {
        "location": {
          "city": "Dearborn", 
          "state": "MI", 
          "country": "United States", 
          . . .
        }, 
        "id": "827346"
      }
    },
    . . .
  ]
}

假设你有一个如下的事件表

Schema::create('events', function(Blueprint $table)
{
    $table->increments('id');
    $table->bigInteger('facebook_id')->nullable()->unsigned()->index();
    $table->string('name')->nullable();
    $table->string('city')->nullable();
    $table->string('state')->nullable();
    $table->string('country')->nullable();
});

下面是如何在你的 Event 模型中将嵌套字段映射到你的数据库表中的方法

use SammyK\LaravelFacebookSdk\SyncableGraphNodeTrait;

class Event extends Eloquent
{
    use SyncableGraphNodeTrait;
    
    protected static $graph_node_field_aliases = [
        'id' => 'facebook_id',
        'place.location.city' => 'city',
        'place.location.state' => 'state',
        'place.location.country' => 'country',
    ];
}

日期格式

Facebook PHP SDK 会将大多数日期格式转换为 DateTime 实例。当你想要将日期/时间值插入到数据库中时(例如,事件节点start_time 字段),这可能会出现问题。

默认情况下,SyncableGraphNodeTrait 会将所有 DateTime 实例转换为以下 date() 格式:

Y-m-d H:i:s

这应该是大多数情况下大多数关系型数据库的适当格式。但这个格式缺少时区,这可能会对你的应用程序很重要。此外,如果你以不同的格式存储日期/时间值,你可能希望自定义 DateTime 实例转换到的格式。为此,只需在你的模型中添加一个 $graph_node_date_time_to_string_format 属性并将其设置为任何 有效的日期格式

use SammyK\LaravelFacebookSdk\SyncableGraphNodeTrait;

class Event extends Eloquent
{
    use SyncableGraphNodeTrait;
    
    protected static $graph_node_date_time_to_string_format = 'c'; # ISO 8601 date
}

将用户登录到 Laravel

Laravel Facebook SDK 使得使用 Laravel 内置的认证驱动器登录用户变得很容易。

更新用户表

为了使 Facebook 认证与 Laravel 内置的认证一起工作,你需要在用户表中存储 Facebook 用户的 ID。

显然,你需要为用户想要保留的每条其他信息创建一个列。

如果你需要在用户不浏览你的应用(例如凌晨 3 点的 cron 作业)时代表用户发出请求,你可以将访问令牌存储在数据库中。但通常你不需要在数据库中存储访问令牌。

你需要生成一个迁移来修改你的 users 表并添加任何新列。

注意:确保将 <name-of-users-table> 更改为你的用户表名称。

$ php artisan make:migration add_facebook_columns_to_users_table --table="<name-of-users-table>"

现在更新迁移文件以包含你想要在用户上保存的新字段。至少你需要保存 Facebook 用户的 ID。

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class AddFacebookColumnsToUsersTable extends Migration
{
    public function up()
    {
        Schema::table('users', function(Blueprint $table)
        {
            // If the primary id in your you user table is different than the Facebook id
            // Make sure it's an unsigned() bigInteger()
            $table->bigInteger('facebook_user_id')->unsigned()->index();
            // Normally you won't need to store the access token in the database
            $table->string('access_token')->nullable();
        });
    }

    public function down()
    {
        Schema::table('users', function(Blueprint $table)
        {
            $table->dropColumn(
                'facebook_user_id',
                'access_token'
            );
        });
    }
}

不要忘记运行迁移。

$ php artisan migrate

如果你打算使用 Facebook 用户 ID 作为主键,确保你有一个名为 id 的列,它是一个无符号的大整数并已索引。如果你在其他字段中存储 Facebook ID,确保该字段存在于数据库中,并确保在模型中将其映射到自定义的 ID 名称。

如果你正在使用Eloquent ORM并将访问令牌存储在数据库中,请确保在User模型中隐藏可能暴露的access_token字段。

别忘了将SyncableGraphNodeTrait添加到你的用户模型中,以便你可以将你的模型与Graph API返回的数据同步。

# User.php
use SammyK\LaravelFacebookSdk\SyncableGraphNodeTrait;

class User extends Eloquent implements UserInterface {
    use SyncableGraphNodeTrait;

    protected $hidden = ['access_token'];
}

在Laravel中登录用户

用户使用Facebook登录并从Graph API获取用户ID后,你可以通过将登录用户的User模型传递给Auth::login()方法来在Laravel中登录用户。

class FacebookController {
    public function getUserInfo(SammyK\LaravelFacebookSdk\LaravelFacebookSdk $fb) {
       try {
           $response = $fb->get('/me?fields=id,name,email');
       } catch (Facebook\Exceptions\FacebookSDKException $e) {
           dd($e->getMessage());
       }
       
       // Convert the response to a `Facebook/GraphNodes/GraphUser` collection
       $facebook_user = $response->getGraphUser();
       
       // Create the user if it does not exist or update the existing entry.
       // This will only work if you've added the SyncableGraphNodeTrait to your User model.
       $user = App\User::createOrUpdateGraphNode($facebook_user);
       
       // Log the user into Laravel
       Auth::login($user);
    }
}

处理多个应用程序

如果你想在同一脚本中使用多个Facebook应用或需要在运行时调整设置,你可以使用自定义设置创建一个新的LaravelFacebookSdk实例。

Route::get('/example', function(SammyK\LaravelFacebookSdk\LaravelFacebookSdk $fb) {
    // All the possible configuration options are available here
    $fb2 = $fb->newInstance([
      'app_id' => env('FACEBOOK_APP_ID2'),
      'app_secret' => env('FACEBOOK_APP_SECRET2'),
      'default_graph_version' => 'v2.9',
      // . . .
    ]);
});

错误处理

Facebook PHP SDK抛出Facebook\Exceptions\FacebookSDKException异常。每当Graph响应错误时,SDK将抛出一个扩展自Facebook\Exceptions\FacebookSDKExceptionFacebook\Exceptions\FacebookResponseException。如果抛出Facebook\Exceptions\FacebookResponseException,你可以通过getPrevious()方法获取与错误相关的特定异常。

try {
    // Stuffs here
} catch (Facebook\Exceptions\FacebookResponseException $e) {
    $graphError = $e->getPrevious();
    echo 'Graph API Error: ' . $e->getMessage();
    echo ', Graph error code: ' . $graphError->getCode();
    exit;
} catch (Facebook\Exceptions\FacebookSDKException $e) {
    echo 'SDK Error: ' . $e->getMessage();
    exit;
}

LaravelFacebookSdk不会抛出任何自定义异常。

故障排除

在使用canvas应用时获取TokenMismatchException

如果你的应用在应用画布或页面标签的上下文中提供服务,当你尝试在Facebook上查看应用时,可能会看到TokenMismatchException错误。这是因为Facebook将通过发送带有signed_request参数的POST请求来渲染你的应用,而Laravel 5对每个非读取请求都启用了CSRF保护,因此触发了错误。

虽然可以完全禁用此功能,但这绝对不推荐,因为CSRF保护是网站的一个重要安全特性,应该默认在所有路由上启用。

在Laravel 5.1 & 5.2中禁用CSRF

将异常添加到你的canvas端点中的$except数组,在你的app\Http\Middleware\VerifyCsrfToken.php文件中。

<?php

namespace App\Http\Middleware;

use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier;

class VerifyCsrfToken extends BaseVerifier
{
    /**
     * The URIs that should be excluded from CSRF verification.
     *
     * @var array
     */
    protected $except = [
        'facebook/canvas',
        'facebook/page-tab',
        // ... insert all your canvas endpoints here
    ];
}

在Laravel 5.0中禁用CSRF

在Laravel 5.0中禁用CSRF验证有些复杂,但有一篇文章解释了如何在Laravel 5.0中禁用特定路由的CSRF保护

在你的app\Http\Middleware\VerifyCsrfToken.php文件中,添加一个excludedRoutes()方法。然后创建一个包含你的画布应用或页面标签端点的路由数组。完整的文件如下

<?php namespace App\Http\Middleware;

use Closure;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier;
use Illuminate\Session\TokenMismatchException;

class VerifyCsrfToken extends BaseVerifier
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     *
     * @throws TokenMismatchException
     */
    public function handle($request, Closure $next)
    {
        if ($this->isReading($request) || $this->excludedRoutes($request) || $this->tokensMatch($request)) {
            return $this->addCookieToResponse($request, $next($request));
        }

        throw new TokenMismatchException;
    }

    /**
     * Ignore CSRF on these routes.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return bool
     */
    private function excludedRoutes($request)
    {
        $routes = [
          'my-app/canvas',
          'my-app/page-tab',
          // ... insert all your canvas endpoints here
        ];

        foreach($routes as $route){
            if ($request->is($route)) {
                return true;
            }
        }

        return false;
    }
}

保存用户时获取QueryException

如果你正在使用MySQL,你可能在使用createOrUpdateGraphNode()将用户保存到数据库时遇到QueryException

QueryException in Connection.php line 754:
SQLSTATE[HY000]: General error: 1364 Field 'password' doesn't have a default value

这是因为默认情况下启用了严格模式,将sql_mode设置为包括STRICT_TRANS_TABLES。由于我们不需要密码,所以这个字段将为空。解决这个错误的办法是在你的config/database.php文件中将MySQL驱动的strict设置为false

测试

测试是用phpunit编写的。你可以使用以下命令从项目目录的根目录运行测试。

$ ./vendor/bin/phpunit

贡献

有关详细信息,请参阅CONTRIBUTING

鸣谢

本包由 Sammy Kaye Powers 维护。查看完整的 贡献者列表

许可

MIT 许可证(MIT)。更多信息请参阅 许可证文件