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

Api Platform OpenApi未自动携带JWT令牌问题求助

问题:ApiPlatform OpenAPI文档授权后请求未自动携带JWT令牌

我用ApiPlatform(PHP 8 / Symfony 6)搭建了带JWT认证的简易API,认证功能正常,能生成令牌。用PostMan手动加Bearer头测试接口没问题,但在自动生成的OpenApi文档里,点击「Authorize」按钮添加令牌后,调用需要认证的接口时,curl请求没自动带上这个令牌。

问题根源

  1. 安全方案名称不匹配:JwtDecorator里定义的安全方案叫JWT,但实体NotificationCategory的openapiContext里用的是Bearer Authentication,名称不一致导致Swagger UI无法关联认证信息。
  2. 全局安全配置缺失:OpenAPI根节点未添加全局安全要求,接口不会默认应用已配置的JWT认证。
  3. Access Control规则过松:最后一条规则把所有接口设为PUBLIC_ACCESS,可能干扰Swagger UI的认证提示逻辑。
  4. 安全方案未正确写入OpenAPI对象:原JwtDecorator仅修改了变量,未将安全方案更新到OpenApi实例中。

修复步骤

1. 统一安全方案名称

修改NotificationCategory的openapiContext,将安全方案名称改为和JwtDecorator一致的JWT:

#[ApiResource(
    openapiContext: ['security' => [['JWT' => []]]],
    security: "is_granted('ROLE_USER')"
)]

2. 补全JwtDecorator的安全方案配置

确保安全方案被正确写入OpenAPI对象,并添加全局安全要求:

<?php

namespace App\OpenApi;

use ApiPlatform\OpenApi\Factory\OpenApiFactoryInterface;
use ApiPlatform\OpenApi\OpenApi;
use ApiPlatform\OpenApi\Model;

final class JwtDecorator implements OpenApiFactoryInterface
{
    public function __construct(
        private OpenApiFactoryInterface $decorated
    ) {}

    public function __invoke(array $context = []): OpenApi
    {
        $openApi = ($this->decorated)($context);
        $schemas = $openApi->getComponents()->getSchemas();

        $schemas['Token'] = new \ArrayObject([
            'type' => 'object',
            'properties' => [
                'token' => [
                    'type' => 'string',
                    'readOnly' => true,
                ],
            ],
        ]);
        $schemas['Credentials'] = new \ArrayObject([
            'type' => 'object',
            'properties' => [
                'username' => [
                    'type' => 'string',
                    'example' => 'test@gmail.com',
                ],
                'password' => [
                    'type' => 'string',
                    'example' => '123456',
                ],
            ],
        ]);

        // 读取现有安全方案,添加JWT配置后重新写入
        $securitySchemes = $openApi->getComponents()->getSecuritySchemes() ?? [];
        $securitySchemes['JWT'] = new \ArrayObject([
            'type' => 'http',
            'scheme' => 'bearer',
            'bearerFormat' => 'JWT',
        ]);
        $openApi->getComponents()->setSecuritySchemes($securitySchemes);

        $pathItem = new Model\PathItem(
            ref: 'JWT Token',
            post: new Model\Operation(
                operationId: 'postCredentialsItem',
                tags: ['Token'],
                responses: [
                    '200' => [
                        'description' => '获取JWT令牌',
                        'content' => [
                            'application/json' => [
                                'schema' => [
                                    '$ref' => '#/components/schemas/Token',
                                ],
                            ],
                        ],
                    ],
                ],
                summary: '获取JWT令牌用于登录',
                requestBody: new Model\RequestBody(
                    description: '生成新的JWT令牌',
                    content: new \ArrayObject([
                        'application/json' => [
                            'schema' => [
                                '$ref' => '#/components/schemas/Credentials',
                            ],
                        ],
                    ]),
                ),
                security: [], // 登录接口无需认证,设为空数组
            ),
        );
        $openApi->getPaths()->addPath('/login', $pathItem);

        // 添加全局安全配置,所有接口默认应用JWT认证
        $openApi = $openApi->withSecurity([['JWT' => []]]);

        return $openApi;
    }
}

3. 调整Access Control规则

收紧全局权限,避免所有接口公开:

security:
    # ... 其他配置保持不变
    access_control:
        - { path: ^/$, roles: PUBLIC_ACCESS } # 允许访问Swagger UI首页
        - { path: ^/docs, roles: PUBLIC_ACCESS } # 允许访问Swagger文档
        - { path: ^/login, roles: PUBLIC_ACCESS }
        - { path: ^/, roles: ROLE_USER } # 其他接口需ROLE_USER权限

4. 清理缓存并测试

执行命令清理Symfony缓存:

php bin/console cache:clear

重新打开Swagger UI,点击「Authorize」添加令牌后调用接口,此时curl请求会自动携带Authorization: Bearer <你的令牌>头。

内容的提问来源于stack exchange,提问作者Aurélien W

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 23:30:45