0

首先,我在我的 laravel 6 应用程序中使用Hyn -Multi Tenant有一个中央数据库 [connection = system] 处理多个租户数据库。到目前为止,这个包对我帮助很大,但我的应用程序需要为 API 实现护照,这在包中没有记录。

但是,还有其他教程声称在 Hyn 包上实现了护照。我跟着他们,能够为每个租户用户创建访问令牌。

这是我的配置/auth.php:

return [
'defaults' => [
        'guard' => 'web',
        'passwords' => 'system-users',
    ],


'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'system',
        ],

        'staff' => [
            'driver' => 'session',
            'provider' => 'staff',
        ],

        'api' => [
            'driver' => 'passport',
            'provider' => 'staff',
            'hash' => false,
        ],
        'student' => [
            'driver' => 'passport',
            'provider' => 'student',
            'hash' => false,
        ],
    ],

'providers' => [
        'system' => [
            'driver' => 'eloquent',
            'model' => App\Models\System\User::class,
        ],
        'staff' => [
            'driver' => 'eloquent',
            'model' => App\Models\Tenant\Staff::class,
        ],
        'student' => [
            'driver' => 'eloquent',
            'model' => App\Models\Tenant\Student::class,
        ],

        // 'users' => [
        //     'driver' => 'database',
        //     'table' => 'users',
        // ],
    ],

我的每个租户模型都使用UsesTenantConnection特征

这是我的 EnforceTenancy 中间件

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Support\Facades\Config;


class EnforceTenancy
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        Config::set('database.default', 'tenant');

        return $next($request);
    }
}

这是我的 AuthServiceProvider.php

public function boot()
    {
        $this->registerPolicies();

        Passport::routes(null, ['middleware' => 'tenancy.enforce']);


        // FOLLOWING CODE IS HAVING PROBLEM
        //Passport::useTokenModel(OAuthAccessToken::class);
        //Passport::useClientModel(OAuthClient::class);
        //Passport::useAuthCodeModel(OAuthCode::class);
        //Passport::usePersonalAccessClientModel(OAuthPersonalAccessClient::class);

        $this->commands([
            \Laravel\Passport\Console\InstallCommand::class,
            \Laravel\Passport\Console\ClientCommand::class,
            \Laravel\Passport\Console\KeysCommand::class,
        ]);

        \Laravel\Passport\Passport::tokensExpireIn(\Carbon\Carbon::now()->addMinutes(10));
        \Laravel\Passport\Passport::refreshTokensExpireIn(\Carbon\Carbon::now()->addDays(1));
    }

到目前为止一切都很好,现在我将分点解释,

  1. 当我打电话createToken('MyApp')时,我能够在租户数据库上生成令牌,例如:
if (Auth::guard('staff')->attempt(['email' => $request->email, 'password' => $request->password])) {

            $user = Auth::guard('staff')->user();

            $auth_tokens = $user->createToken('MyApp');

            $access_token = $auth_tokens->accessToken;
...
}

但要访问受登录保护的 api,我在标头中发送不记名访问令牌

window.axios
                .get("/api/meta",{
                    headers: fetchAuthHeaders()
                })
                .then(response => {
                    if(true == response.data.status) {
                        var data = response.data.data;
                        this.school.name = data.school_meta.name;
                        this.school.logo = data.school_meta.logo;
                    } else{
                        alert(response.data.message);
                    }

                })

api.php

Route::domain('{hostname}.lvh.me')->group(function () {
    Route::middleware('tenant.exists')->group(function () {
        Route::get('/get-oauth-secret', 'Tenant\MetaController@getOAuthData');
        Route::post('validate-login','Tenant\AuthController@validateLogin');

        Route::middleware(['auth:api'])->group(function (){
            Route::get('meta','Tenant\AuthController@getMetaData'); //this api
        });
    });

});

我得到回应{"message":"Unauthenticated."}

  1. 在步骤 1 中生成令牌后,我复制此令牌并粘贴到邮递员的标题部分并取消注释 AuthServiceProvider.php 中的自定义护照模型,如下所示

AuthServiceProvider.php

public function boot()
    {
        ...


        // UNCOMMENTED FOLLOWING CUSTOM PASSPORT MODELS
        Passport::useTokenModel(OAuthAccessToken::class);
        Passport::useClientModel(OAuthClient::class);
        Passport::useAuthCodeModel(OAuthCode::class);
        Passport::usePersonalAccessClientModel(OAuthPersonalAccessClient::class);

        ...
    }

现在我可以访问api/meta路由,但是在登录和创建令牌时出现错误:

ErrorException: Trying to get property 'id' of non-object in file /home/winlappy1/Desktop/multi_tenancy/vendor/laravel/passport/src/PersonalAccessTokenFactory.php on line 98

我只是想知道我哪里出错了,我知道我的解释非常模棱两可和令人困惑,但这就是我可以解释我的问题的全部方式。我准备提供更多说明,但我需要解决这个问题。

4

2 回答 2

1

还使用支持多重身份验证的 Laravel Passport 9.1.0

尝试这样做@AuthServiceProvider

添加这个

    public function boot()
    {
        $this->registerPolicies();

This one is to check if the database is Tenant or not 
        $website   = \Hyn\Tenancy\Facades\TenancyFacade::website();
        if ($website != null) {
            Passport::useClientModel(PassportClient::class);
            Passport::useTokenModel(PassportToken::class);
            Passport::useAuthCodeModel(PassportAuthCode::class);
            Passport::usePersonalAccessClientModel(PassportPersonalAccessClient::class);
        }

        $this->commands([
            \Laravel\Passport\Console\InstallCommand::class,
            \Laravel\Passport\Console\ClientCommand::class,
            \Laravel\Passport\Console\KeysCommand::class,
        ]);

        \Laravel\Passport\Passport::tokensExpireIn(\Carbon\Carbon::now()->addMinutes(10));
        \Laravel\Passport\Passport::refreshTokensExpireIn(\Carbon\Carbon::now()->addDays(1));
    }

随着这些添加四个模型像这样

创建四个执行租户的模型

   use Hyn\Tenancy\Traits\UsesTenantConnection;
    use Laravel\Passport\AuthCode;

    class PassportAuthCode extends AuthCode
    {use UsesTenantConnection;}

    use Hyn\Tenancy\Traits\UsesTenantConnection;
    use Laravel\Passport\Client;

    class PassportClient extends Client
    {use UsesTenantConnection;}

    use Hyn\Tenancy\Traits\UsesTenantConnection;
    use Laravel\Passport\PersonalAccessClient;

    class PassportPersonalAccessClient extends PersonalAccessClient
    {use UsesTenantConnection;}

    use Hyn\Tenancy\Traits\UsesTenantConnection;
    use Laravel\Passport\Token;

    class PassportToken extends Token
    {use UsesTenantConnection;}

也使用 (tenancy.enforce) 中间件 Enforcetenancy 'tenancy.enforce' => \App\Http\Middleware\EnforceTenancy::class, $Routemiddleware kernel.php

EnforceTenancy.php 中间件

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Config;

class EnforceTenancy
{
    /**
     * Handle an incoming request.
     *
     * @param  Request  $request
     * @param Closure $next
     *
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        Config::set('database.default', 'tenant');

        return $next($request);
    }
}

通过 tenancy.enforce 中间件强制租户路由

同时发布新的迁移和 migrate:fresh 新字段添加到新护照

于 2020-05-11T14:16:14.583 回答
1

尝试添加

\App\Http\Middleware\EnforceTenancy::class

进入 Kernel.php 中 $middlewarePriority 数组的开头

于 2020-02-17T08:29:39.057 回答