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

Api-platform中基于JWT用户筛选多对多关联Team集合的问题

实现方案

1. 确保实体关联配置正确

先确认User和Team的多对多关联配置无误(Team为关系拥有方):

User 实体

<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity]
class User
{
    // ... 其他属性和方法

    /**
     * @ORM\ManyToMany(targetEntity=Team::class, inversedBy="users")
     */
    private $teams;

    // 构造函数、getter/setter 略
}

Team 实体

<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity]
class Team
{
    // ... 其他属性和方法

    /**
     * @ORM\ManyToMany(targetEntity=User::class, mappedBy="teams")
     * @ORM\JoinTable(name="user_team") // 若中间表名非默认可手动指定
     */
    private $users;

    // 构造函数、getter/setter 略
}

2. 编写自定义查询扩展类

创建CurrentUserTeamExtension类,通过API Platform的ORM扩展机制实现数据过滤,无需手动关联中间表(Doctrine会自动处理多对多的中间表关联逻辑):

<?php

namespace App\ApiPlatform\Extension;

use ApiPlatform\Doctrine\Orm\Extension\QueryCollectionExtensionInterface;
use ApiPlatform\Doctrine\Orm\Extension\QueryItemExtensionInterface;
use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface;
use App\Entity\Team;
use App\Entity\User;
use Doctrine\ORM\QueryBuilder;
use Symfony\Bundle\SecurityBundle\Security;

final class CurrentUserTeamExtension implements QueryCollectionExtensionInterface, QueryItemExtensionInterface
{
    public function __construct(private readonly Security $security)
    {
    }

    public function applyToCollection(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, string $operationName = null): void
    {
        $this->addUserFilter($queryBuilder, $resourceClass);
    }

    public function applyToItem(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, array $identifiers, string $operationName = null, array $context = []): void
    {
        $this->addUserFilter($queryBuilder, $resourceClass);
    }

    private function addUserFilter(QueryBuilder $queryBuilder, string $resourceClass): void
    {
        // 仅对Team实体生效,管理员角色跳过过滤(可根据需求调整)
        if ($resourceClass !== Team::class || $this->security->isGranted('ROLE_ADMIN')) {
            return;
        }

        $currentUser = $this->security->getUser();
        if (!$currentUser instanceof User) {
            return;
        }

        $rootAlias = $queryBuilder->getRootAliases()[0];
        // 通过Team的users关联自动关联中间表,生成符合预期的SQL逻辑
        $queryBuilder->innerJoin(sprintf('%s.users', $rootAlias), 'u');
        $queryBuilder->andWhere('u.id = :currentUserId');
        $queryBuilder->setParameter('currentUserId', $currentUser->getId());
    }
}

3. 注册扩展服务

确保扩展类被Symfony容器识别,在config/services.yaml中添加标签(Symfony 6+ 若使用自动注册可省略,但手动添加更稳妥):

services:
    App\ApiPlatform\Extension\CurrentUserTeamExtension:
        tags:
            - { name: api_platform.doctrine.orm.query_extension.collection }
            - { name: api_platform.doctrine.orm.query_extension.item }

效果说明

配置完成后:

  • 用户通过JWT登录后,GET /teams接口仅返回该用户所属的团队
  • GET /teams/{id}接口会自动验证该团队是否属于当前用户(非管理员角色下),不属于则返回404

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 16:01:07