服務端和 Web 端分離架構下使用 passport 進行前後臺使用者各自的認證

dreamfish發表於2018-09-21

前段時間(大概一年以前)寫了個專案使用了前後端程式碼分離的架構,同時又因為業務需要出現了管理端和前臺商戶端兩套使用者表登陸的需求。

因為使用了 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 的資料就可以了

有夢想的鹹魚

相關文章