You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Symfony 6中如何在请求头中发送JWT Token?

JWT Token存储与后续请求携带问题解决方案

问题梳理

你已经通过LexikJWTAuthenticationBundle实现了JWT功能,API Platform的登录接口能正常返回Token和用户数据,但不清楚如何存储Token,并在后续请求的Authorization头中以Bearer方式携带。你尝试写了一个TokenListener,但思路存在偏差,下面帮你理清正确的做法。

你的代码问题分析

你写的TokenListener完全没必要,而且存在逻辑错误:

  1. kernel.response事件是在当前请求处理完毕、准备返回响应时触发的,此时修改当前请求的Authorization头对后续请求没有任何作用——后续请求是全新的HTTP请求,和当前请求无关。
  2. $jwtManager->create($token)用法错误:create方法需要传入User对象来生成新Token,而不是传入已有的Token字符串,这一步完全是多余的。

另外,你在services.yaml中自定义的lexik_jwt_authentication.token_extractor和lexik_jwt_authentication.jwt_manager属于重复配置,LexikJWTBundle已经默认提供了这些服务,除非有特殊需求,否则应该删掉,避免冲突。

正确的解决方案

JWT的核心是客户端存储Token,后续请求主动携带,后端只需要负责验证Token的有效性即可,不需要干预Token的存储和携带过程。

1. 客户端(前端/移动端)场景

登录成功后,客户端把返回的Token存在本地存储,后续请求手动添加Authorization头:

// 登录请求示例(JavaScript)
fetch('/api/login_check', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    username: 'user@example.com',
    password: 'your-password'
  })
})
.then(res => res.json())
.then(data => {
  // 将Token存入localStorage(也可以用sessionStorage或Cookie)
  localStorage.setItem('jwt_token', data.token);
});

// 后续授权请求示例
const token = localStorage.getItem('jwt_token');
fetch('/api/protected-resource', {
  headers: {
    'Authorization': `Bearer ${token}`
  }
})
.then(res => res.json())
.then(data => {
  // 处理受保护资源的响应
});

2. 后端内部服务调用场景

如果是后端内部需要调用其他授权接口,可以通过以下方式携带Token:

// 控制器示例
namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Contracts\HttpClient\HttpClientInterface;
use Symfony\Component\HttpFoundation\Response;

class InternalCallController extends AbstractController
{
    public function callProtectedApi(HttpClientInterface $httpClient): Response
    {
        // 从当前请求的头中获取已验证的Token(适用于当前请求已授权的场景)
        $token = $this->get('lexik_jwt_authentication.token_extractor')->extract($this->getRequest());

        // 调用内部API并携带Token
        $response = $httpClient->request('GET', 'https://your-internal-api/protected-endpoint', [
            'headers' => [
                'Authorization' => 'Bearer ' . $token,
            ],
        ]);

        $data = $response->toArray();

        return $this->json($data);
    }
}

3. 保留你的有效代码

你现有的JWTCreatedListener和LoginSuccessListener是正确的,不需要修改:

  • JWTCreatedListener:给JWT的payload添加IP信息,给header添加cty字段,没问题。
  • LoginSuccessListener:在登录成功响应中添加用户详细信息,符合需求。

最终操作步骤

  1. 删除TokenListener类文件。
  2. 从services.yaml中删除以下配置:
    lexik_jwt_authentication.token_extractor:
        class: Lexik\Bundle\JWTAuthenticationBundle\TokenExtractor\AuthorizationHeaderTokenExtractor
        arguments:
            - 'Bearer'
            - 'Authorization'
    
    lexik_jwt_authentication.jwt_manager:
        class: Lexik\Bundle\JWTAuthenticationBundle\Services\JWTManager
        arguments:
            - '@lexik_jwt_authentication.encoder'
            - '@event_dispatcher'
            - '@lexik_jwt_authentication.key_loader'
            - '@lexik_jwt_authentication.token_extractor'
    
  3. 按照上述客户端或后端内部调用的示例,实现Token的存储与携带。

内容的提问来源于stack exchange,提问作者RookieCoder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 17:11:11