服务端和 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 的数据就可以了

本作品采用《CC 协议》,转载必须注明作者和本文链接
本帖由系统于 2年前 自动加精
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
讨论数量: 7
ThinkCsly

很好,谢谢

2年前 评论
Toiu

如果对完整OAuth系统不是那么依赖, 只是做api鉴权. 用 jwt-auth 可能会方便快捷许多, 只需要定义多个guard就行了

1年前 评论

@Toiu jwt没有太多的了解!不过,passport 本身也是支持多 guard 的,然而对于多用户模型的认证似乎还是有些问题!

1年前 评论
Toiu

@dreamfish 使用多guard大部分场景就是为了能用多用户模型认证吧. jwt-auth 这个包还是很不错的. passport用过但是没有太深入了解过,对仅仅想使用api认证的场景来说. 个人认为略微重了一丢丢. 多 guard更是不太理想

1年前 评论

@dreamfish 我想请问一下 关于手机号和验证码登录 passport对于oauth2的有没有优雅的实现,一直在纠结

1年前 评论

@jake_zou 验证码加手机属于无密码授权,可以采用个人令牌的方式实现!

1年前 评论

League \ OAuth2 \ Server \ Exception \ OAuthServerException (3) The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed.

file

不知道为什么在AuthServiceProvider里面加以下代码就报错了

file

7个月前 评论
snowlyg (楼主) 7个月前

请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!