Api Platform OpenApi未自动携带JWT令牌问题求助
问题:ApiPlatform OpenAPI文档授权后请求未自动携带JWT令牌
我用ApiPlatform(PHP 8 / Symfony 6)搭建了带JWT认证的简易API,认证功能正常,能生成令牌。用PostMan手动加Bearer头测试接口没问题,但在自动生成的OpenApi文档里,点击「Authorize」按钮添加令牌后,调用需要认证的接口时,curl请求没自动带上这个令牌。
问题根源
- 安全方案名称不匹配:
JwtDecorator里定义的安全方案叫JWT,但实体NotificationCategory的openapiContext里用的是Bearer Authentication,名称不一致导致Swagger UI无法关联认证信息。 - 全局安全配置缺失:OpenAPI根节点未添加全局安全要求,接口不会默认应用已配置的JWT认证。
- Access Control规则过松:最后一条规则把所有接口设为
PUBLIC_ACCESS,可能干扰Swagger UI的认证提示逻辑。 - 安全方案未正确写入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
相关产品推荐
相关产品推荐

