claudiorodrigo / passport-multiauth
为 Laravel Passport 添加多认证支持
Requires
- php: ^7.2
- laravel/passport: ^8.0
Requires (Dev)
- mockery/mockery: ^1.0
- orchestra/database: ^4.0
- orchestra/testbench: ^4.0
README
为 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\Passport 的 scope 和 scopes 中间件。
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 Tokens 和 Personal Access Token 的完整 Passport-Multiauth 实现。
贡献者
基于 renanwilian 对 Passport Multi-Auth issue 的响应。