为 collectionOperations 实施 ApiResource 安全过滤规则

Implement ApiResource security filter rule for collectionOperations

是否可以在实体上实现 ApiResource 安全性,以便没有实体 ID 的 GET 请求(即收集操作)returns 只有与当前经过身份验证的用户匹配的项目(或者,为此目的,任何其他必须针对每个实体检查的规则)?

到目前为止我的实施:

/**
 * @ORM\Entity(repositoryClass=UserRepository::class)
 * @ORM\Table(name="`user`")
 * @ApiResource(
 *     attributes={"security"="is_granted('ROLE_USER')"},
 *     collectionOperations={"get"={"security"="is_granted('ROLE_ADMIN') or object == user"}},
 *     itemOperations={"get"={"security"="is_granted('ROLE_ADMIN') or object == user"}},
 *     )
 */
class User implements UserInterface
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    private ?int $id;

   // ...

}

上面的代码适用于项目操作,但不适用于集合操作符,即假定用户标识。 1(不是管理员)已通过身份验证:

为此使用 Doctrine Extension。这不是安全问题,您不想限制对资源的访问,而是想修改返回的结果。

例如,草草修改链接文档上的示例:

final class CurrentUserExtension implements QueryCollectionExtensionInterface
{

    public function __construct(private Security $security)
    {
    }

    public function applyToCollection(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, string $operationName = null): void
    {
        if (User::class !== $resourceClass
            || $this->security->isGranted('ROLE_ADMIN')
            || null === $user = $this->security->getUser())
        {
            return;
        }

        $rootAlias = $queryBuilder->getRootAliases()[0];
        $queryBuilder->andWhere(sprintf('%s.id = :current_user', $rootAlias));
        $queryBuilder->setParameter('current_user', $user->getId());
    }

}