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

能否针对特定用户角色生成对应权限的OpenAPI接口文档?

API Platform基于角色生成对应权限的OpenAPI文档方案

结论

这个需求完全可以实现,API Platform预留了OpenAPI文档的自定义扩展能力,你可以通过重写文档生成逻辑,结合当前登录用户的角色做过滤即可。

核心实现思路

通过自定义OpenApiFactory装饰器,在原有自动生成的OpenAPI文档基础上,做两层过滤:

  • 第一层:过滤掉当前用户角色无权限访问的接口路径
  • 第二层:过滤掉接口返回Schema中当前用户角色无权限查看的属性

具体操作步骤

  • 第一步:创建自定义OpenAPI工厂类
    在项目的src/OpenApi/目录下新建RoleBasedOpenApiFactory.php文件,代码示例如下:
<?php

namespace App\OpenApi;

use ApiPlatform\OpenApi\Factory\OpenApiFactoryInterface;
use ApiPlatform\OpenApi\OpenApi;
use ApiPlatform\OpenApi\Model\PathItem;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;

class RoleBasedOpenApiFactory implements OpenApiFactoryInterface
{
    public function __construct(
        private OpenApiFactoryInterface $decorated,
        private TokenStorageInterface $tokenStorage,
        private AuthorizationCheckerInterface $authorizationChecker
    ) {}

    public function __invoke(array $context = []): OpenApi
    {
        $openApi = ($this->decorated)($context);
        $token = $this->tokenStorage->getToken();
        if (!$token || !$token->getUser()) {
            // 匿名用户逻辑,只返回公开接口
            return $this->filterPublicPaths($openApi);
        }

        // 过滤无权限的接口路径
        $paths = $openApi->getPaths()->getPaths();
        $filteredPaths = new \ArrayObject();
        foreach ($paths as $path => $pathItem) {
            if ($this->isPathAllowed($pathItem, $token)) {
                $filteredPaths[$path] = $pathItem;
            }
        }
        $openApi = $openApi->withPaths(new \ApiPlatform\OpenApi\Model\Paths($filteredPaths));

        // 过滤Schema里无权限的属性
        $components = $openApi->getComponents();
        $schemas = $components->getSchemas();
        $filteredSchemas = new \ArrayObject();
        foreach ($schemas as $schemaName => $schema) {
            $filteredSchema = $this->filterSchemaProperties($schema, $token);
            $filteredSchemas[$schemaName] = $filteredSchema;
        }
        $openApi = $openApi->withComponents($components->withSchemas($filteredSchemas));

        return $openApi;
    }

    private function isPathAllowed(PathItem $pathItem, $token): bool
    {
        // 替换为你自己的接口权限校验逻辑,比如读取该路径ApiResource的security配置校验
        // 示例:如果路径需要ROLE_ADMIN,当前用户没有就返回false
        return true;
    }

    private function filterSchemaProperties($schema, $token): object
    {
        // 替换为你自己的属性权限校验逻辑,过滤掉当前用户无权限查看的属性
        return $schema;
    }

    private function filterPublicPaths(OpenApi $openApi): OpenApi
    {
        // 替换为你自己的公开接口过滤逻辑
        return $openApi;
    }
}
  • 第二步:注册装饰器服务
    在config/services.yaml中添加服务配置,将自定义类注册为原生OpenAPI工厂的装饰器:
# config/services.yaml
services:
    App\OpenApi\RoleBasedOpenApiFactory:
        decorates: 'api_platform.openapi.factory'
        arguments: ['@.inner']
        # 优先级可按需调整,数值越高越先执行
        priority: -10
  • 第三步:实现你的权限校验逻辑
    上面代码中的isPathAllowed、filterSchemaProperties方法需要你根据自己项目的权限规则实现:
    • 如果你是通过ApiResource注解的security属性配置的接口权限,可以直接读取该路径对应资源的权限表达式,通过AuthorizationCheckerInterface校验当前用户是否有权限
    • 如果你是通过ApiProperty注解的security属性配置的属性权限,读取对应属性的权限表达式校验后,从Schema的属性列表中移除无权限的属性,同时同步更新Schema的required字段
  • 第四步:适配匿名用户场景
    如果你的接口支持匿名访问,在filterPublicPaths方法中实现公开接口的过滤逻辑即可。

注意事项

要额外注意OpenAPI文档的缓存问题:默认API Platform会缓存生成的OpenAPI内容,如果你需要不同角色看到不同文档,需要修改缓存配置,将用户角色加入缓存键,或者在开发环境关闭缓存,生产环境按角色做缓存分区,避免不同权限的用户拿到同一份缓存文档。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 19:48:01