smartins/passport-multiauth

为 Laravel Passport 添加多认证支持

v7.0.0 2020-04-03 00:08 UTC

README

由于 Laravel Password 自 9.0 版本起已提供原生实现,因此该包已过时,具体信息请见 版本 9.0

Laravel Passport Multi-Auth

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 数组中添加一个新的 guard,使用驱动程序 passport 和上面添加的提供者

    // ...

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

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

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

    // ...

app/Http/Kernel.php 文件中将中间件 AddCustomProvider 注册到 $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,
    ];

    // ...
}

注意:中间件 AddCustomProvider 的参数 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,
    ];

    // ...
}

AuthServiceProvider 中封装 passport 路由的访问令牌,使用已注册的中间件。此中间件将添加能力到 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"
}

您可以根据需要将 guards 传递给 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 guard 的用法与 admin 例子相同。

您可以将多个 guards 传递给 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 中使用默认 guard web。例如

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

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

单元测试

而不是使用 Laravel\Passport\Passport::actingAs() 方法,请使用 SMartins\PassportMultiauth\PassportMultiauth::actingAs()。区别在于此包的 actingAs 根据第一个参数传递的 Authenticatable 实例获取 guard 并使用您的 guard 认证此用户。在认证请求(使用包中的 auth 中间件 - SMartins\PassportMultiauth\Http\Middleware\MultiAuthenticate) 中,将在 Request 上检查 guard 以返回用户或抛出 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 项目中看到一个完整的 Passport-Multiauth 实现,使用 Password Grant TokensPersonal Access Token

贡献者

基于 renanwilianPassport Multi-Auth 问题 的回复。