首页 > 解决方案 > 如何在 API 平台中对“GET 项目”请求的 SQL 请求之前验证 UUID 参数?

问题描述

使用:

我有一个具有以下 ID 的实体:

/**
 * @ORM\Entity(repositoryClass="App\Repository\ContractRepository")
 * @ORM\HasLifecycleCallbacks
 */
class Contract
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue(strategy="UUID")
     * @ORM\Column(name="id", type="guid", unique=true)
     */
    private $id;
[...]

我使用 Api Platform 生成以下路线:

App\Entity\Contract:
  itemOperations:
    get:

所以我得到了一个生成的路线/contracts/{id}

目前,如果我这样做/contracts/TEST,它将尝试在 where 子句中使用“TEST”执行 SQL 请求,因此将作为500.

我想通过断言{id}参数是 aUUID_v4并返回 a400如果不是来防止这种行为。

标签: symfonysymfony4api-platform.com

解决方案


此行为是 DBMS 特定的,因此您必须添加自己的逻辑。

检索给定 ID 的实体的 API 平台组件是ItemDataProviderInterface

  1. 首先,我将声明一个新的异常MalformedUuidException
  2. 接下来,我会将此异常转换为 400 错误
  3. 最后,我将创建一个新的 ItemDataProviderInterface 实现,包装 ORM 并向 ID 添加一些检查:
class ContractDataProvider implements RestrictedDataProviderInterface, ItemDataProviderInterface
{
    /** @var ItemDataProviderInterface */
    private $realDataProvider;

    public function __construct(ItemDataProviderInterface $realDataProvider)
    {
        $this->realDataProvider = $realDataProvider;
    }

    public function getItem(string $resourceClass, $id, string $operationName = null, array $context = [])
    {
        $uuidPattern = '/^[a-f0-9]{8}-([a-f0-9]{4}-){3}[a-f0-9]{12}$/i';
        if (preg_match($uuidPattern, $id) === 1) {
            return $this->realDataProvider->getItem($resourceClass, ['id' => $id], $operationName, $context);
        } else {
            throw new MalformedUuidException("the given ID \"$id\" is not a valid UUID.");
        }
    }

    public function supports(string $resourceClass, string $operationName = null, array $context = []): bool
    {
        return $resourceClass === Contract::class;
    }
}
# config/services.yaml
    App\DataProvider\ContractDataProvider:
        arguments:
            $realDataProvider: '@api_platform.doctrine.orm.default.item_data_provider'

但是,请注意,该getItem()方法的协定并未指定MalformedUuidException异常,因此此实现打破了 Liskov 替换原则。

考虑改为返回 null 并对 404 错误感到满意。


推荐阅读