leandrodiogenes/passport-multiauth

为Laravel Passport添加多认证支持

v6.0.1 2020-03-12 14:00 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 包发现中删除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数组中使用驱动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,
    ];

    // ...
}

注意:中间件AddCustomProviderprovider参数是必需的。您必须传递在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路由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 守卫的用法与 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 中使用默认的守卫 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 问题 的回复。