如何在 Laravel 中进行 JWT cookie 身份验证

Kam*_*ski 6 authentication api cookies jwt laravel-5

我想在 Laravel >=5.2 中进行 JWT 身份验证,使用这个(Tymon JWT-auth)库,但我想将 JWT 令牌放入 HttpOnly Cookies - 以保护 JWT 令牌免受 XSS 攻击。

  1. 我设置了 Tymon 库并...在项目中:app/Providers/RouteServiceProvider@mapWebRoutes 我php artisan route:list通过删除'middleware' => 'web'(如果我不这样做)为所有请求停用执行'web'中间件组(这是默认的laravel行为 - 你可以看到它)不这样做,我会看到 post 请求的 CSRF 问题)。
  2. 在routes.php我写:
Route::group(['middleware' =>'api', 'prefix' => '/api/v1', 'namespace' => 'Api\V1'], function () {
    Route::post('/login', 'Auth\AuthController@postLogin');
    ...
    Route::get('/projects', 'ProjectsController@getProjects');
}
Run Code Online (Sandbox Code Playgroud)
  1. 在可能 Api\V1\Auth\AuthController@postLogin 我生成令牌并将其作为 httpOnly cookie 发送回:

    ...
    try
    {
        $user = User::where('email','=',$credentials['email'])->first();
    
        if ( !($user && Hash::check($credentials['password'], $user->password) ))
        {
            return response()->json(['error' => 'invalid_credentials'], 401);
        }
    
        $customClaims = ['sub' => $user->id, 'role'=> $user->role, 'csrf-token' => str_random(32) ];
        $payload = JWTFactory::make($customClaims);
        $token = JWTAuth::encode($payload);
    } catch(...) {...}
    return response()->json($payload->toArray())->withCookie('token', $token, config('jwt.ttl'), "/", null, false, true); 
    
    Run Code Online (Sandbox Code Playgroud)
  2. 而且,是的,问题开始了。我想Auth对每个请求做一些事情(可能是修改 laravel类):

    • 从请求中获取 cookie
    • 解码它
    • 检查是正确的(如果不是 trhow 401)
    • 从数据库获取用户
    • 并使该方法 Auth::user() 像在 laravel 中的通常方式一样在任何地方工作(例如,我可以在每个控制器中使用它)

任何想法如何做第4点?

更新

我还在此处添加了对 CSRF 攻击的保护 - csrf-token 在 JWT 中,它也在登录请求的响应正文中返回(因此 JS 可以访问此 csrf-token)(我仅在登录时返回 JWT 令牌的公共部分响应,整个 JWT 仅在 cookie 中返回,因此它是 XSS 安全的) - 然后前端 JS 必须将 csrf-token 复制到每个请求的标头中。然后中间件 JWTAuthentiacate(在我下面的回答中)将 csrf-token 标头与 JWT 有效负载中的 csrf-token 字段进行比较 - 如果它们相似,则请求通过 csrf 测试。

小智 3

您可以通过创建中间件来简单地做到这一点。

在handle()方法中,只需从请求中获取cookie,对其进行解码并使用此Laravel方法使用id登录用户:

Auth::loginUsingId($userIdFromToken);
Run Code Online (Sandbox Code Playgroud)