如何为特定角色隐藏API文档及/api入口中的指定端点?
针对特定角色隐藏API端点文档(保留端点可用)的实现方案
下面提供几种简便的实现方式,仅隐藏文档和/api入口中的端点展示,实际接口仍可被有权限的用户正常调用:
方法一:通过OpenAPI事件监听器动态过滤端点
利用Symfony的事件机制,在API Platform生成OpenAPI文档时,根据当前用户角色过滤掉不需要展示的端点:
// src/EventListener/OpenApiFilterListener.php namespace App\EventListener; use ApiPlatform\Core\EventListener\EventPriorities; use ApiPlatform\Core\OpenApi\OpenApi; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\Security\Core\Security; class OpenApiFilterListener implements EventSubscriberInterface { private $security; public function __construct(Security $security) { $this->security = $security; } public static function getSubscribedEvents() { return [ KernelEvents::REQUEST => ['filterOpenApi', EventPriorities::PRE_READ], ]; } public function filterOpenApi(RequestEvent $event) { $request = $event->getRequest(); // 仅处理API文档相关请求 if (!$request->attributes->get('_api_operation_name') || !in_array($request->getPathInfo(), ['/api/docs.json', '/api/docs.jsonld', '/api'])) { return; } $user = $this->security->getUser(); // 非管理员用户则过滤指定端点 if (!$user || !$this->security->isGranted('ROLE_ADMIN')) { /** @var OpenApi $openApi */ $openApi = $request->attributes->get('_api_openapi'); $paths = $openApi->getPaths(); // 示例:移除非管理员不应看到的删除用户端点 $paths->offsetUnset('/users/{id}'); // 可批量添加需要过滤的路径,或通过正则匹配批量处理 $openApi->setPaths($paths); $request->attributes->set('_api_openapi', $openApi); } } }
方法二:自定义OpenAPI文档处理器(API Platform 2.6+)
采用装饰器模式扩展API Platform的OpenAPI生成逻辑,支持更精细的控制(比如仅隐藏某个HTTP方法而非整个路径):
// src/OpenApi/OpenApiProcessor.php namespace App\OpenApi; use ApiPlatform\Core\OpenApi\Factory\OpenApiFactoryInterface; use ApiPlatform\Core\OpenApi\OpenApi; use ApiPlatform\Core\OpenApi\Model\PathItem; use Symfony\Component\Security\Core\Security; class OpenApiProcessor implements OpenApiFactoryInterface { private $decorated; private $security; public function __construct(OpenApiFactoryInterface $decorated, Security $security) { $this->decorated = $decorated; $this->security = $security; } public function __invoke(array $context = []): OpenApi { $openApi = $this->decorated->__invoke($context); $user = $this->security->getUser(); // 非管理员用户过滤指定接口 if (!$user || !$this->security->isGranted('ROLE_ADMIN')) { $paths = $openApi->getPaths(); // 示例:仅移除/users/{id}的DELETE方法,保留GET/PUT等其他方法 if ($paths->offsetExists('/users/{id}')) { /** @var PathItem $pathItem */ $pathItem = $paths->offsetGet('/users/{id}'); $pathItem->setDelete(null); $paths->offsetSet('/users/{id}', $pathItem); } $openApi->setPaths($paths); } return $openApi; } }
注册这个装饰器(在services.yaml中):
services: App\OpenApi\OpenApiProcessor: decorates: 'api_platform.openapi.factory' arguments: ['@.inner', '@security.helper']
方法三:结合注解自动过滤(更灵活)
在实体的API操作注解中定义权限,然后让处理器自动识别并过滤无权限的端点:
// src/Entity/User.php use ApiPlatform\Core\Annotation\ApiResource; use Symfony\Component\Security\Core\Annotation\IsGranted; /** * @ApiResource( * operations={ * "delete"={ * "security"="is_granted('ROLE_ADMIN')", * "openapi_context"={ * "summary"="仅管理员可见的删除用户接口" * } * }, * "get"={ * "security"="is_granted('ROLE_USER')" * } * } * ) */ class User { // 实体字段... }
然后在之前的OpenApiProcessor中,遍历所有路径的操作,检查security规则,自动过滤当前用户无权限的操作,避免硬编码路径,扩展性更强。
以上方案均仅隐藏文档中的端点展示,实际接口仍可被拥有对应角色权限的用户正常调用,完全满足你的需求。
内容的提问来源于stack exchange,提问作者To Ny
相关产品推荐
相关产品推荐

