Symfony 6中如何在请求头中发送JWT Token?
JWT Token存储与后续请求携带问题解决方案
问题梳理
你已经通过LexikJWTAuthenticationBundle实现了JWT功能,API Platform的登录接口能正常返回Token和用户数据,但不清楚如何存储Token,并在后续请求的Authorization头中以Bearer方式携带。你尝试写了一个TokenListener,但思路存在偏差,下面帮你理清正确的做法。
你的代码问题分析
你写的TokenListener完全没必要,而且存在逻辑错误:
kernel.response事件是在当前请求处理完毕、准备返回响应时触发的,此时修改当前请求的Authorization头对后续请求没有任何作用——后续请求是全新的HTTP请求,和当前请求无关。$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:在登录成功响应中添加用户详细信息,符合需求。
最终操作步骤
- 删除
TokenListener类文件。 - 从
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' - 按照上述客户端或后端内部调用的示例,实现Token的存储与携带。
内容的提问来源于stack exchange,提问作者RookieCoder
相关产品推荐
相关产品推荐

