服务端和web端分离架构下使用 passport 进行前后台用户各自的认证
服务端和web端分离架构下使用 passport 进行前后台用户各自的认证
前段时间(大概一年以前)写了个项目使用了前后端代码分离的架构,同时又因为业务需要出现了管理端和前台商户端两套用户表登陆的需求。
因为使用了 passport 包做登陆认证,但是passport又不支持多用户系统认证。所以那时候使用了一个中间表的方式去做认证,这种方式可以解决问题,但是太过复杂。
最近有个新的项目,又遇到了同样的问题所以网上找了一下是否有简单的解决方案,果然找到了一个轮子用sfelix-martins/passport-multiauth,使用它可以简单的实现,前后台分离架构下使用 passport 进行前后端用户各自的认证。
这里要感谢下 Samuel Martins 为我们提供了这么优秀的轮子,目前已经更新到3.0版本。
具体的使用方法,其实看文档基本已经很简单了。不过这里还是简单的写一下我使用的过程。
在此之前,你需要看过使用 passport 的相关教程
1.引入 smartins/passport-multiauth
composer require smartins/passport-multiauth
2.迁移数据表 oauth_access_token_providers
php artisan migrate
3.在需要认证的模型内引入 HasMultiAuthApiTokens
use Illuminate\Notifications\Notifiable; use Illuminate\Foundation\Auth\User as Authenticatable; use SMartins\PassportMultiauth\HasMultiAuthApiTokens; class Admin extends Authenticatable { use Notifiable, HasMultiAuthApiTokens; }
4.在 config/auth.php providers 数组内增加对应的 provider
// ... 'providers' => [ 'users' => [ 'driver' => 'eloquent', 'model' => App\User::class, ], // ** New provider** 'admins' => [ 'driver' => 'eloquent', 'model' => App\Admin::class, ], ],
5.在 config/auth.php guards 数组内增加对应的 guard
// ... 'guards' => [ 'web' => [ 'driver' => 'session', 'provider' => 'users', ], 'api' => [ 'driver' => 'passport', 'provider' => 'users', ], // ** New guard ** 'admin' => [ 'driver' => 'passport', 'provider' => 'admins', ], ], // ...
5.在 app/Http/Kernel.php 的 $routeMiddleware 数组内增加 AddCustomProvider 中间件。
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, 'auth' => \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, ]; // ... }
6.在 AuthServiceProvider 里面增加对应的路由
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(); }); }); } // ... }
7.运行 vendor:publish
php artisan vendor:publish --provider="SMartins\PassportMultiauth\Providers\MultiauthServiceProvider"
8.在使用 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" }
到此基本就可以进行多表的认证了。
在使用过程中遇到过一个小问题,因为我是先使用 passport ,在开发过程中为了方便直接把对应的 oauth_client 表是直接用 seeder 填充的,这也样就省去了每次重置数据表的时候还需要再次运行 passport:install 去生成数据。当我使用 Personal Access Tokens 的时候会报一个错误
Trying to get property 'client' of non-boject at >>>\\vendor\laravel\\passport\\src\\ClientRepository.php:81
这个问题是因为 oauth_personal_access_clients 表里面没有数据,增加一条 oauth_personal_access_client 的数据就可以了