#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