首页 > 解决方案 > API 平台 access_control:无法访问私有财产

问题描述

我正在尝试对对象的所有者实施访问控制。我正在使用 LexikJWTAuthenticationBundle,当我将检查限制为角色时,访问控制有效,但在检查对象属性时会引发异常。

我正在使用 composer 在 Symfony 4.3 项目上安装的 API 平台。PHP 是 7.2.19。

我可以通过检查角色成功地限制对登录用户的请求,但是当添加类似“object.owner == user”的内容时,它会失败并显示“hydra:description”:“无法访问私有财产 App\Entity\Vehicle::$所有者”

这是具有相关字段的实体类。

/**
 * @ApiResource(
 *     collectionOperations={"get"={"access_control"="is_granted('ROLE_USER')"}, "post"={"access_control"="is_granted('ROLE_USER')"}},
 *     itemOperations={"get"={"access_control"="is_granted('ROLE_USER') and object.owner == user"}, "put"={"access_control"="is_granted('ROLE_USER') and previous_object.owner == user"}},
 *     normalizationContext={"groups"={"vehicle:read"}},
 *     denormalizationContext={"groups"={"vehicle:write"}}
 * )
 * @ORM\Entity(repositoryClass="App\Repository\VehicleRepository")
 * @ApiFilter(SearchFilter::class, properties={"owner": "exact"})
 */
class Vehicle
{
    /**
     * @Assert\NotBlank()
     * @ORM\ManyToOne(targetEntity="App\Entity\User", inversedBy="vehicles")
     * @ORM\JoinColumn(nullable=false)
     * @Groups({"vehicle:read", "vehicle:write"})
     */
    private $owner;

    public function getOwner(): User
    {
        return $this->owner;
    }
}

这应该只允许拥有用户获取或更新车辆,但它总是以“hydra:description”失败:“无法访问私有财产 App\Entity\Vehicle::$owner”。

如果我删除了“object.owner == user”注释,但保留了 ROLE_USER 的检查,则允许该操作。

标签: api-platform.com

解决方案


有两种方法可以解决这个问题:

  1. 更改属性所有者的可见性,即“ public owner ”而不是“ private owner ”(注意:不好的做法,因为它违反了封装原则);
  2. 而不是 object.owner,只需编写 object.getOwner() 和 previous_object.getOwner()。因为所有者属性是私有的,所以访问它的唯一方法是通过它的访问器,如下所示:

        /**
         * @ApiResource(
         *     collectionOperations={"get"={"access_control"="is_granted('ROLE_USER')"}, "post"={"access_control"="is_granted('ROLE_USER')"}},
         *     itemOperations={"get"={"access_control"="is_granted('ROLE_USER') and object.getOwner() == user"}, "put"={"access_control"="is_granted('ROLE_USER') and previous_object.getOwner() == user"}},
         *     normalizationContext={"groups"={"vehicle:read"}},
         *     denormalizationContext={"groups"={"vehicle:write"}}
         * )
         * @ORM\Entity(repositoryClass="App\Repository\VehicleRepository")
         * @ApiFilter(SearchFilter::class, properties={"owner": "exact"})
         */
    class Vehicle
    {
        /**
         * @Assert\NotBlank()
         * @ORM\ManyToOne(targetEntity="App\Entity\User", inversedBy="vehicles")
         * @ORM\JoinColumn(nullable=false)
         * @Groups({"vehicle:read", "vehicle:write"})
         */
        private $owner;
    
        public function getOwner(): User
        {
            return $this->owner;
        }
    }
    

推荐阅读