Сбой нескольких одновременных запросов в одном сеансе

#laravel #laravel-8

Вопрос:

У меня есть проект Laravel 8. Когда несколько запросов выполняются с использованием одного и того же сеанса одновременно, Auth::user() возвращает null некоторые запросы в моем поставщике услуг.

Например, при загрузке страницы и на стороне клиента с использованием AngularJS мы выполняем 3 одновременных запроса JSON для получения данных после onload . 2 из 3 запросов JSON завершаются неудачно, потому что в моем поставщике услуг Authorization::user() возвращается значение null.

  • Во всех запросах идентификатор сеанса всегда правильный, проблема не в том, что информация о сеансе не предоставляется.
  • В моем промежуточном программном обеспечении я вызываю Authorization::user() , который каждый раз успешно возвращает пользователя, включая все одновременные запросы.
  • В моем поставщике услуг при вызове Authorization::user() с несколькими одновременными запросами происходит сбой некоторых запросов.

Как мне исправить своего поставщика услуг?

Мой поставщик услуг

 class MyServiceProvider extends ServiceProvider
{
    public function register()
    {
        $this->app->singleton('permissions', function() {

            // we have already checked Auth::user() in middleware
            // before getting here, this should never fail
            // this fails 2 of 3 times when accessed simultaneously
            // with same session

            $u = Auth::user();
            if (empty($u)) {
                Log::error(__METHOD__, ['singleton' => 'permissions', 'error' => 'invalid_user']);
                return new PermissionCache(0);
            }
            return new PermissionCache($u->employeeId);
        });
    }
}
 

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

 class MyApiMiddleware
{
    public function handle($request, Closure $next)
    {
        // this always works for all requests
        
        $u = Auth::user();
        if (empty($u)) {
            Log::error(__METHOD__, ['url' => $request->url(), 'session' => $request->session()->getId(), 'error' => 'user_invalid']);
            return Response::json(ExceptionHelper::CreateToArray('invalidAuthorization'), 500);
        }
        
        // the following fails when it should be good
        // because in MyServiceProvider, sometimes
        // Auth::user() returns null even though
        // above it worked perfectly, as it should
        
        $p = App::make('permissions');
        if (!$p->allowSomthing()) {
            Log::error(__METHOD__, ['url' => $request->url(), 'session' => $request->session()->getId(), 'error' => 'permission_invalid']);
            return Response::json(ExceptionHelper::CreateToArray('invalidAuthorization'), 500);
        }
        
    }
}
 

My Middleware Declaration:

 class Kernel extends HttpKernel
{
    protected $middleware = [
        // AppHttpMiddlewareTrustHosts::class,
        AppHttpMiddlewareTrustProxies::class,
        FruitcakeCorsHandleCors::class,
        AppHttpMiddlewarePreventRequestsDuringMaintenance::class,
        IlluminateFoundationHttpMiddlewareValidatePostSize::class,
        AppHttpMiddlewareTrimStrings::class,
//        IlluminateFoundationHttpMiddlewareConvertEmptyStringsToNull::class,
    ];

    protected $middlewareGroups = [
        'public' => [
//        AppHttpMiddlewareEncryptCookies::class,
            IlluminateCookieMiddlewareAddQueuedCookiesToResponse::class,
            IlluminateSessionMiddlewareStartSession::class,
            IlluminateViewMiddlewareShareErrorsFromSession::class,
            AppHttpMiddlewareVerifyCsrfToken::class,
            IlluminateRoutingMiddlewareSubstituteBindings::class,
        ],
        'session' => [
//        AppHttpMiddlewareEncryptCookies::class,
            IlluminateCookieMiddlewareAddQueuedCookiesToResponse::class,
            IlluminateSessionMiddlewareStartSession::class,
            IlluminateViewMiddlewareShareErrorsFromSession::class,
            AppHttpMiddlewareVerifyCsrfToken::class,
            IlluminateRoutingMiddlewareSubstituteBindings::class,
            MySessionMiddleware::class,
        ],
        'api' => [
//        AppHttpMiddlewareEncryptCookies::class,
            IlluminateCookieMiddlewareAddQueuedCookiesToResponse::class,
            IlluminateSessionMiddlewareStartSession::class,
            IlluminateViewMiddlewareShareErrorsFromSession::class,
            IlluminateRoutingMiddlewareSubstituteBindings::class,
            MyApiMiddleware::class,
        ],
    ];

}
 

Конфигурация сеанса, используемые значения по умолчанию:

 return [
    'driver' => env('SESSION_DRIVER', 'file'),
    'lifetime' => env('SESSION_LIFETIME', 120),
    'expire_on_close' => FALSE,
    'encrypt' => FALSE,
    'files' => storage_path('framework/sessions'),
    'connection' => env('SESSION_CONNECTION', NULL),
    'table' => 'sessions',
    'store' => env('SESSION_STORE', NULL),
    'lottery' => [2, 100],
    'cookie' => env(
        'SESSION_COOKIE',
        Str::slug(env('APP_NAME', 'laravel'), '_') . '_session'
    ),
    'path' => '/',
    'domain' => env('SESSION_DOMAIN', NULL),
    'secure' => env('SESSION_SECURE_COOKIE'),
    'http_only' => TRUE,
    'same_site' => 'lax',
];
 

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

1. Задействованы ли токены CSRF? Возможно, это может быть проблемой (последующие запросы аннулируют предыдущие токены).

2. Нет, это не CSRF. Ошибка в прошлом.

Ответ №1:

Моя проблема заключалась в том, что я пытался получить значение сеанса/аутентификации в моей конструкции контроллера::__. Информация о сеансе в запросе при инициализации контроллера еще не загружена. Мои модульные тесты не уловили этого, потому что эта информация была высмеяна, и мой проект обновляется с laravel 4.2, в котором это работало.