Паспорт Laravel дает ошибку 401 Unauthenticated

Я использую паспорт Laravel для аутентификации API, он отлично работает, когда я использую его с одной БД, но выдает 401 при использовании нескольких баз данных,

Что я делаю:

  • У меня мультитенантная БД, в основной БД есть пользователи, роли и все таблицы OAuth.
  • Когда я создаю пользователя с ролью администратора, он создает новую базу данных с именем администратора, создает дополнительную базу данных с пользователями, ролями и всей таблицей OAuth. oauth_clients дочерней БД скопирует токен предоставления пароля и токен личного доступа из главной БД и вставит его в вспомогательную БД, а также вставит client_id в oauth_personal_access_clients.
  • Я делаю все процедуры, которые выполняет команда passport:install. (Если я что-то не пропустил).

  • Когда я вхожу с учетными данными из основной БД, это работает отлично, реальная проблема начинается, когда я вхожу с учетными данными из под-базы данных, я могу получить под БД из параметра client_code, который я ввел с помощью email, password во время входа в систему.

  • Это позволяет мне войти в систему из дополнительной БД, но я получаю ошибку 401 Unauthenticated, получаю токен доступа при входе в систему и передаю заголовок Authentication с Bearer при каждом запросе после входа в систему с Angular.

  • Не знаю, чего мне здесь не хватает.

Промежуточное программное обеспечение DBConnection

Промежуточное ПО DBConnection устанавливает соединение по каждому запросу после входа в систему,

public function handle($request, Closure $next)
    {
        if ( $request->method() != 'OPTIONS' ) {            
            $this->access_code = $request->header('access-code'); 
            if ( $this->access_code != '' && $this->access_code != 'sa'  ) {
                app('App\Http\Controllers\Controller')->setDB(AppHelper::DB_PREFIX.$this->access_code);
            } else {
                app('App\Http\Controllers\Controller')->setDB(AppHelper::DB_DEFAULT);
            }
        }
        return $next($request);
    }

DBConnection динамически устанавливает базу данных по умолчанию в database.php, для этого я вызываю метод setDB, созданный в Controller.php

setDB Controller.php

public function setDB($database='') {
      $config = app()->make('config');
      $connections = $config->get('database.connections');
      $default_connection = $connections[$config->get('database.default')];
      $new_connection = $default_connection;
      $new_connection['database'] = $database;
      $config->set('database.connections.'.$database, $new_connection);
      $config->set('database.default', $database);
  }

Можно ли использовать passport с 2 разными БД для одного и того же кода?

Laravel 5.4 Passport 4.0 Angular 4.4 в передней части

Ответ 1

Чтобы ответить на ваш вопрос: да, вы можете!

В нашем промежуточном программном обеспечении мы делаем примерно следующее:

config([
  'database.connections.tenant.schema' => $tenant
]);

DB::connection('tenant')->statement("SET search_path = $tenant");

Мне действительно кажется, что ваш search_path не настроен должным образом. Это объясняет, почему вы получаете 401. Поскольку Laravel Passport выполняет поиск в неправильной базе данных, в которой он не может найти правильный токен в вашей таблице пользователей.

Из документов PostgreSQL (https://www.postgresql.org/docs/9.1/static/runtime-config-client.html):

search_path (строка)

Эта переменная указывает порядок поиска схем, когда объект (таблица, тип данных, функция и т.д.) ссылается на простое имя без указанной схемы. Когда в разных схемах есть объекты одинаковых имен, используется первая, найденная в пути поиска. Объект, который не находится ни в одной из схем в пути поиска, может ссылаться только на указание его содержащей схемы с квалифицированным (пунктирным) именем.

Ответ 2

Это проблема CORS. Запрос OPTIONS не доставляет заголовки авторизации.

Если источник отличается от хоста, браузер отправит ОПЦИИ перед любым другим запросом.

Laravel ответит со статусом 401, если не установлено промежуточное программное обеспечение CORS.

Таким образом, в архитектуре RESTful, если хост клиентского приложения отличается от хоста API, вы должны использовать промежуточное программное обеспечение CORS.

Вы можете использовать это: barryvdh/Laravel-CORS

$ composer require barryvdh/laravel-cors

Пример:

App\Http\Kernel.php

protected $routeMiddleware = [
    ...
    'auth.cors' => \Barryvdh\Cors\HandleCors::class,
    ...
];

web.php

Route::group([
    'prefix' => 'api',
    'middleware' => [
        'auth.cors'
    ]
], function () {
    Route::post('user/authenticate', '[email protected]');
});

Если промежуточное программное обеспечение CORS работает должным образом, браузер должен получить статус 200 по запросу OPTIONS и запустить первоначальный запрос с полезной нагрузкой.