同一会话上的多个同时请求失败

时间:2021-06-29 20:57:54

标签: laravel laravel-8

我有一个 Laravel 8 项目。当同时使用同一个会话发出多个请求时,\Auth::user() 会针对我的服务提供者中的某些请求返回 null

例如,当页面加载并在客户端使用 AngularJS 时,我们在 onload 之后同时发出 3 个 JSON 数据请求。 3 个 JSON 请求中有 2 个失败,因为在我的服务提供商中,\Authorization::user() 返回 null。

  • 在所有请求中,会话 ID 始终正确,问题不在于未提供会话信息。
  • 在我的中间件中,我调用了 \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);
        }
        
    }
}

我的中间件声明:

class Kernel extends HttpKernel
{
    protected $middleware = [
        // \App\Http\Middleware\TrustHosts::class,
        \App\Http\Middleware\TrustProxies::class,
        \Fruitcake\Cors\HandleCors::class,
        \App\Http\Middleware\PreventRequestsDuringMaintenance::class,
        \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
        \App\Http\Middleware\TrimStrings::class,
//        \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
    ];

    protected $middlewareGroups = [
        'public' => [
//        \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],
        'session' => [
//        \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
            MySessionMiddleware::class,
        ],
        'api' => [
//        \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::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 个答案:

答案 0 :(得分:0)

我的问题是我试图在我的控制器 ::__construct 中获取 session/auth 值。控制器初始化时请求中的会话信息尚未加载。我的单元测试没有发现这个,因为这个信息被嘲笑了,我的项目正在从 laravel 4.2 升级,这个版本起作用了。

相关问题