Выдача паспорта Laravel с правом аренды для Laravel

#php #laravel #multi-tenant #laravel-passport

Вопрос:

Я создаю мультитенантный проект laravel на основе поддоменов, используя аренду Для Laravel, все работает нормально, за исключением случаев, когда я пытаюсь аутентифицировать свои запросы API с помощью Passport. Сейчас это работает так: у меня есть основная база данных (несколько арендаторов), в которой я объявляю арендаторов и указываю соответствующий поддомен, а затем у каждого арендатора есть своя собственная база данных (tenantfoo). Я прохожу проверку подлинности::, и учетные данные проверяются в правильной базе данных, но когда я пытаюсь создать токен, он перестает использовать базу данных арендатора (tenantfoo) и пытается создать токен в основной базе данных (мультитенант) и выдает следующее исключение.

 SQLSTATE[42S02]: Base table or view not found: 1146 Table 'multi-tenant.oauth_personal_access_clients' doesn't exist
(SQL: select exists(select * from `oauth_personal_access_clients`) as `exists`)
 

при условии, что если я попытаюсь использовать User::all(); пользователей, я получу правильных пользователей, принадлежащих соответствующему арендатору.

Я попытался следовать интеграции с паспортом из их документов, но у меня ничего не вышло..

Итак, что я спрашиваю, есть ли способ вручную создать мой токен?

Я пытался сделать это, но все равно выдает ту же ошибку

 public function loginManual() {
 if (Auth::attempt(['email' => $email, 'password' => $password, 'active' => 1])) {
            $token = Auth::user()->createToken('Laravel Password Grant Client')->accessToken;
                $response = ['token' => $token];
                return $response
        } else {
            $response = ["message" => "Password mismatch"];
            return $response
        }
}
 

Ниже прилагается часть кода, не стесняйтесь спрашивать о чем-либо, что не предусмотрено.

AppServiceProvider.php

 <?php

namespace AppProviders;

use IlluminateSupportFacadesSchema;
use IlluminateSupportServiceProvider;
use LaravelPassportPassport;
use StanclTenancyMiddlewareInitializeTenancyByDomain;
use StanclTenancyMiddlewarePreventAccessFromCentralDomains;
use IlluminateSupportFacadesRoute;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        Passport::ignoreMigrations();
        Passport::routes(null, ['middleware' => [
            // You can make this simpler by creating a tenancy route group
            InitializeTenancyByDomain::class,
            PreventAccessFromCentralDomains::class,
        ]]);
    }

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        Passport::loadKeysFrom(base_path(config('passport.key_path')));
        Schema::defaultStringLength(191);
    }
}

 

AuthServiceProvider.php

 <?php

namespace AppProviders;

use IlluminateFoundationSupportProvidersAuthServiceProvider as ServiceProvider;
use IlluminateSupportFacadesGate;
use LaravelPassportPassport;
use StanclTenancyMiddlewareInitializeTenancyByDomain;
use StanclTenancyMiddlewarePreventAccessFromCentralDomains;

class AuthServiceProvider extends ServiceProvider
{
    /**
     * The policy mappings for the application.
     *
     * @var array
     */
    protected $policies = [
        // 'AppModelsModel' => 'AppPoliciesModelPolicy',
    ];

    /**
     * Register any authentication/authorization services.
     *
     * @return void
     */
    public function boot()
    {
        $this->registerPolicies();

        Passport::routes();

    }
}
 

Ответ №1:

Поэтому в итоге я создал промежуточное программное обеспечение и вручную на лету изменил базу данных на правильную. И добавил промежуточное программное обеспечение к Passport::routes(); инициализации. Таким образом, все паспортные маршруты будут проверены по правильной базе данных.

Класс промежуточного программного обеспечения:

 class ChangeDatabaseConnection
{
    /**
     * Handle an incoming request.
     *
     * @param  IlluminateHttpRequest  $request
     * @param  Closure  $next
     * @return mixed
     */
    public function handle(Request $request, Closure $next)
    {
        if ($request->tenant != 'www' amp;amp; $request->tenant != NULL) {
            $db_name = 'tenant'. $request->tenant;
            DB::disconnect(); 
            Config::set('database.connections.mysql.database', $db_name); 
            DB::reconnect();
            $db = Config::get('database.connections.mysql.database');
            return $next($request);
        } else {
            $url = $request->url();
            $parsedUrl = parse_url($url);
            $host = explode('.', $parsedUrl['host']);
            $subdomain = $host[0];
            if ($subdomain != NULL amp;amp; $subdomain != 'www') {
                $db_name = 'tenant'. $subdomain;
                DB::disconnect(); 
                Config::set('database.connections.mysql.database', $db_name); 
                DB::reconnect();
                $db = Config::get('database.connections.mysql.database');
                return $next($request);
            }
        }
        
        return $next($request);
    }
}
 

Декларация паспортных маршрутов (AuthServiceProvider):

  Passport::routes(null, ['middleware' => ['pre-db']]);
 

Я изменяю базу данных только тогда, когда предоставляется клиент (не «www»), в противном случае используется основная база данных (объявленная в .env). Это отлично работает для меня, если я столкнусь с какими-либо проблемами, я обновлю свой ответ тем, как я их решаю.

Комментарии:

1. Просто небольшое замечание, во время поиска другой ошибки, связанной с паспортом, я думаю, что нашел более элегантное решение вашей проблемы github.com/archtechx/tenancy/issues/505#issuecomment-703140978