claudiorodrigo/passport-multiauth

为 Laravel Passport 添加多认证支持

v6.1.0 2020-03-23 14:45 UTC

README

Latest Stable Version Build Status Code Coverage Scrutinizer Code Quality StyleCI License Donate

Laravel Passport 添加多认证支持

从 4.0 升级到 5.0

  • 要从 4.0 版本升级到 5.0,请遵循 本指南

从 2.0 升级到 3.0

  • 要从 2.0 版本升级到 3.0,请遵循 本指南

从 1.0 升级到 2.0

  • 要从 1.0 版本升级到 2.0,请遵循 本指南

兼容性

安装和配置

使用 Composer 安装

$ composer require smartins/passport-multiauth

为了确保一切正常工作,我们需要确保在 Laravel\Passport\PassportServiceProvider::class 之前注册了 SMartins\PassportMultiauth\Providers\MultiauthServiceProvider::class 服务提供者。

首先,您需要从 Laravel Package Discovery 中移除 laravel/passport 包。

在您的 composer.json 文件中,将 laravel/passport 添加到 extra.laravel.dont-discover 数组

    "extra": {
        "laravel": {
            "dont-discover": [
                "laravel/passport"
            ]
        }
    },

并在 config/app.php 上手动注册提供者

    'providers' => [
        // ...
        SMartins\PassportMultiauth\Providers\MultiauthServiceProvider::class,
        Laravel\Passport\PassportServiceProvider::class,
    ],

警告:服务提供者 SMartins\PassportMultiauth\Providers\MultiauthServiceProvider::class 必须在 Laravel\Passport\PassportServiceProvider::class 之前添加,以确保其正常工作。

您可能需要清除引导缓存文件以重新注册提供者

php artisan optimize:clear

迁移数据库以创建 oauth_access_token_providers

$ php artisan migrate

注意:如果您没有运行安装 passport 的命令,请运行以下命令

$ php artisan passport:install

与从 Laravel Passport 核心中使用的 Laravel\Passport\HasApiTokens 特性不同,请使用特性 SMartins\PassportMultiauth\HasMultiAuthApiTokens

在内部,此 HasMultiAuthApiTokens 使用 HasApiTokens,重写 tokens()createToken($name, $scopes = []) 方法。方法 tokens() 的行为已更改,以便与 oauth_access_token_providers 表联合,仅获取为特定模型创建的令牌。方法 createToken($name, $scopes = []) 已更改,以使用在 config/auth.php 中定义的 provider 创建令牌。现在,当您创建令牌时,此令牌将与调用模型的模型相关联。

config/auth.php 中使用扩展 Authenticatable 类的模型添加新的提供者,并使用 HasMultiAuthApiTokens 特性。

示例

配置您的模型

use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
use SMartins\PassportMultiauth\HasMultiAuthApiTokens;

class Admin extends Authenticatable
{
    use Notifiable, HasMultiAuthApiTokens;
}

和您的 config/auth.php 提供者

    // ...

    'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => App\User::class,
        ],

        // ** New provider**
        'admins' => [
            'driver' => 'eloquent',
            'model' => App\Admin::class,
        ],
    ],

    // ...

config/auth.php 的 guards 数组中使用 driver passport 添加新的 guard,并使用上面添加的提供者

    // ...

    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],

        'api' => [
            'driver' => 'passport',
            'provider' => 'users',
        ],

        // ** New guard **
        'admin' => [
            'driver' => 'passport',
            'provider' => 'admins',
        ],
    ],

    // ...

将中间件 AddCustomProvider 注册到 app/Http/Kernel.php 文件上的 $routeMiddleware 属性。

class Kernel extends HttpKernel
{
    // ...

    /**
     * The application's route middleware.
     *
     * These middleware may be assigned to groups or used individually.
     *
     * @var array
     */
    protected $routeMiddleware = [
        // ...
        'oauth.providers' => \SMartins\PassportMultiauth\Http\Middleware\AddCustomProvider::class,
    ];

    // ...
}

注意:参数 provider 对于 AddCustomProvider 中间件包装的路由是必需的。您必须传递在 config/auth.php 上配置的有效提供者。

app/Http/Kernel$routeMiddleware 属性上添加新的中间件 Authenticate

class Kernel extends HttpKernel
{
    // ...

    /**
     * The application's route middleware.
     *
     * These middleware may be assigned to groups or used individually.
     *
     * @var array
     */
    protected $routeMiddleware = [
        'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
        // ** New middleware **
        'multiauth' => \SMartins\PassportMultiauth\Http\Middleware\MultiAuthenticate::class,
        'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
        'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
        'can' => \Illuminate\Auth\Middleware\Authorize::class,
        'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
        'oauth.providers' => \SMartins\PassportMultiauth\Http\Middleware\AddCustomProvider::class,
        'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
    ];

    // ...
}

将 passport 的访问令牌路由封装在 AuthServiceProvider 上注册的中间件中。此中间件将向 Passport 路由 oauth/token 添加使用请求上 provider 参数的能力

namespace App\Providers;

use Route;
use Laravel\Passport\Passport;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;

class AuthServiceProvider extends ServiceProvider
{
    // ...

    /**
     * Register any authentication / authorization services.
     *
     * @return void
     */
    public function boot()
    {
        $this->registerPolicies();

        Passport::routes();

        // Middleware `oauth.providers` middleware defined on $routeMiddleware above
        Route::group(['middleware' => 'oauth.providers'], function () {
            Passport::routes(function ($router) {
                return $router->forAccessTokens();
            });
        });
    }
    // ...
}

可选:发布迁移

只需运行带有包提供者参数的 vendor:publish artisan 命令

$ php artisan vendor:publish --provider="SMartins\PassportMultiauth\Providers\MultiauthServiceProvider"

如果您不打算使用 PassportMultiauth 的默认迁移,请在您的 AppServiceProvider 的 register 方法中调用 SMartins\PassportMultiauth\PassportMultiauth::ignoreMigrations 方法。

用法

/oauth/token 请求中添加 provider 参数

POST /oauth/token HTTP/1.1
Host: localhost
Accept: application/json, text/plain, */*
Content-Type: application/json;charset=UTF-8
Cache-Control: no-cache

{
    "username":"user@domain.com",
    "password":"password",
    "grant_type" : "password",
    "client_id": "client-id",
    "client_secret" : "client-secret",
    "provider" : "admins"
}

您可以根据需要将您的守卫传递给 multiauth 中间件。例如:

Route::group(['middleware' => ['api', 'multiauth:admin']], function () {
    Route::get('/admin', function ($request) {
        // Get the logged admin instance
        return $request->user(); // You can use too `$request->user('admin')` passing the guard.
    });
});

api 守卫的使用与 admin 的示例相同。

您可以向 multiauth 中间件传递多个守卫。

Route::group(['middleware' => ['api', 'multiauth:admin,api']], function () {
    Route::get('/admin', function ($request) {
        // The instance of user authenticated (Admin or User in this case) will be returned
        return $request->user();
    });
});

您还可以使用 Auth 门面。

Auth::check();
Auth::user();

刷新令牌

/oauth/token 请求中添加 provider 参数

POST /oauth/token HTTP/1.1
Host: localhost
Accept: application/json, text/plain, */*
Content-Type: application/json;charset=UTF-8
Cache-Control: no-cache

{
    "grant_type" : "refresh_token",
    "client_id": "client-id",
    "client_secret" : "client-secret",
    "refresh_token" : "refresh-token",
    "provider" : "admins"
}

使用作用域

只需使用来自 Laravel\Passportscopescopes 中间件。

protected $routeMiddleware = [
    'scopes' => \Laravel\Passport\Http\Middleware\CheckScopes::class,
    'scope' => \Laravel\Passport\Http\Middleware\CheckForAnyScope::class,
];

个人访问令牌

在您的使用 SMartins\PassportMultiauth\HasMultiAuthApiTokens 特性的模型中,您可以使用 createToken($name, $scopes = [])tokens() 方法来管理您的个人访问令牌。例如:

$user = User::find(1);
$admin = Admin::find(1);

// Create token from Model instance.
$user->createToken('My Token');
$admin->createToken('My Admin Token');

// Get the tokens created to this user. 
$user->tokens()->each(function ($token) {
    echo $token->name; // My Token
});

$admin->tokens()->each(function ($token) {
    echo $token->name; // My Admin Token
});

已知问题

要使所有功能正常工作,您必须在 config/auth.php 中使用默认守卫 web。例如:

    'defaults' => [
        'guard' => 'web',
    ],

存在一个已打开的 问题,将尽快分析。

单元测试

而不是使用 Laravel\Passport\Passport::actingAs() 方法,请使用 SMartins\PassportMultiauth\PassportMultiauth::actingAs()。区别在于,此包中的 actingAs 会根据传递给第一个参数的 Authenticatable 实例获取守卫,并使用您的守卫来认证此用户。在认证请求中(使用来自包的 auth 中间件 - SMartins\PassportMultiauth\Http\Middleware\MultiAuthenticate),将检查 Request 中的守卫以返回用户或抛出 Unauthenticated 异常。例如:

use App\User;
use Tests\TestCase;
use SMartins\PassportMultiauth\PassportMultiauth;

class AuthTest extends TestCase
{
    public function fooTest()
    {
        $user = factory(User::class)->create();

        PassportMultiauth::actingAs($user);

        $this->json('GET', 'api/user');
    }

    public function withScopesTest()
    {
        $user = factory(User::class)->create();

        PassportMultiauth::actingAs($user, ['see-balance']);

        $this->json('GET', 'api/balance');
    }
}

示例项目

您可以在 passport-multiauth-demo 项目中看到使用 Password Grant TokensPersonal Access Token 的完整 Passport-Multiauth 实现。

贡献者

基于 renanwilianPassport Multi-Auth issue 的响应。