Symfony 不使用自定义子资源路径时关系实体字段上的安全投票者

Symfony 不使用自定义子资源路径时关系实体字段上的安全投票者,symfony,api-platform.com,Symfony,Api Platform.com,我已经开始在我们的应用程序中做一些更高级的安全性工作,公司可以为每个模块创建自己的用户角色,使用可自定义的CRUD,这意味着您可以创建一个自定义角色“Users read only”,将“read”设置为“2”,并为用户模块创建、更新、删除为0。团队模块也是如此 0表示他根本没有访问权限 1表示可以访问公司下的所有数据 2意味着只能访问与他相关的东西(如果他是所有者 (另一个用户的) 这将导致这样一种行为,即当用户通过get请求请求团队时,它将返回团队中包含用户的团队,但是,由于用户角色配置

我已经开始在我们的应用程序中做一些更高级的安全性工作,公司可以为每个模块创建自己的用户角色,使用可自定义的CRUD,这意味着您可以创建一个自定义角色“Users read only”,将“read”设置为“2”,并为用户模块创建、更新、删除为0。团队模块也是如此

  • 0表示他根本没有访问权限
  • 1表示可以访问公司下的所有数据
  • 2意味着只能访问与他相关的东西(如果他是所有者 (另一个用户的)
这将导致这样一种行为,即当用户通过get请求请求团队时,它将返回团队中包含用户的团队,但是,由于用户角色配置了
$capabilities[“users”][“read”]=2
,因此
团队。用户
应该只包含他,而不包含其他团队成员,因为用户只能看到他自己和他创建的用户

到目前为止,我已经使用实现
QueryCollectionExtensionInterface
并过滤出要返回给用户的结果的条令扩展来限制collection get操作:

  • 当我使用具有
    $capabilities[“teams”][“read”]=2
    的角色进行查询时,集合只返回用户所属的团队或他创建的团队
  • 当我查询具有
    $capabilities[“teams”][“read”]=1
    角色的用户时,它将返回公司内的所有团队。这是正确的
当我询问一个团队时,问题就来了。对于项目操作的安全性,我使用投票者,它在获取/更新/插入/之前检查用户功能。。。将一个新实体添加到DB中,该实体工作正常

所以问题是,当团队返回时,manytomany userteam关系中的用户列表包含团队中的所有用户。我需要以某种方式过滤掉它,以匹配我的角色能力。因此,在这种情况下,如果用户具有
$capabilities[“users”][“read”]=2
,那么
team.users
应该只包含发出请求的用户,因为他有权列出他所在的团队,但除了他自己之外,他没有查看其他用户的权限

所以我的问题是,如何在关系字段上为项操作和集合操作添加安全投票器

我想要达到的目标的粗略的视觉表现

    /**
     * @ORM\ManyToMany(targetEntity="User", mappedBy="teams")
     * @Groups({"team.read","form.read"})
     * @Security({itemOperations={
 *         "get"={
 *              "access_control"="is_granted('user.view', object)",
 *              "access_control_message"="Access denied."
 *          },
 *         "put"={
 *              "access_control"="is_granted('user.update', object)",
 *              "access_control_message"="Access denied."
 *          },
 *         "delete"={
 *              "access_control"="is_granted('user.delete', object)",
 *              "access_control_message"="Access denied."
 *          },
 *      },
 *      collectionOperations={
 *          "get"={
 *              "access_control"="is_granted('user.list', object)",
 *              "access_control_message"="Access denied."
 *          },
 *          "post"={
 *              "access_control"="is_granted('user.create', object)",
 *              "access_control_message"="Access denied."
 *          },
 *      }})
     */
    private $users;

考虑到数据库查询已经完成,从性能角度来看,我认为Normalizer不是一个好的解决方案。

如果我理解得很好,最后唯一的问题是,当您发出请求时,
GET/api/teams/{id}
,属性
$users
包含属于该团队的所有用户,但给定用户的权限,您只需要显示一个子集

事实上,条令扩展是不够的,因为它们只限制目标实体的实体数量,即在您的情况下
团队

但是它似乎涵盖了这个用例;它们允许向查询中添加额外的SQL子句,即使在获取关联实体时也是如此。但我自己从来没有用过,所以我不能百分之百肯定。似乎是一个非常低级的工具

否则,我将在我的项目中处理一个类似的用例,但我不确定它是否满足您的所有需求:

  • 添加一个额外的
    $members
    数组属性,不带任何
    @ORM
    注释
  • 从序列化中排除
    $users
    关联属性,将其替换为
    $members
  • 装饰
    团队
    实体的数据提供程序
  • 使修饰的数据提供程序使用一组受限的用户填充新属性
//src/Entity/Team.php
/**
*@ApiResource(
*     ...
* )
*@ORM\Entity(repositoryClass=TeamRepository::class)
*/
班队
{
/**
*@ORM\Id
*@ORM\GeneratedValue
*@ORM\Column(type=“integer”)
*/
私人$id;
/**
*@var User[]
*@ORM\ManyToMany(targetEntity=User::class)//此属性已持久化,但未序列化
*/
私人用户;
/**
*@var User[]//此属性不是持久化的,而是序列化的
*@Groups({read:team,…})
*/
私人$members=[];
//src/DataProvider/TeamDataProvider.php
类TeamDataProvider实现CollectionDataProviderInterface、ItemDataProviderInterface、RestrictedDataProviderInterface
{
/**@var ItemDataProvider*/
私人$itemDataProvider;
/**@var CollectionDataProvider*/
私人$collectionDataProvider;
/**@var安全*/
私人保安;
公共函数构造(ItemDataProvider$ItemDataProvider,
CollectionDataProvider$CollectionDataProvider,
保证金(美元保证金)
{
$this->itemDataProvider=$itemDataProvider;
$this->collectionDataProvider=$collectionDataProvider;
$this->security=$security;
}
公共函数支持(字符串$resourceClass,字符串$operationName=null,数组$context=[]):bool
{
返回$resourceClass==Team::class;
}
公共函数getCollection(字符串$resourceClass,字符串$operationName=null)
{
/**@var团队[]$manyTeams*/
$manyTeams=$this->collectionDataProvider->getCollection($resourceClass,$operationName);
foreach($团队中的许多单位){
$this->FillMembersDependengUserPermissions($team);
}
返回$manyTeams;
}
公共函数getItem(字符串$resourceClass,$id,字符串$operationName=null,数组$context=[]))
{
/**@var Team |空$Team*/
$team=$this->itemDataProvider->getItem($resourceClass,['id'=>$id],$operationName,$context);
如果($team!==null){
$this->FillMembersDependengUserPermissions($team);
}
返回