Symfony 不使用自定义子资源路径时关系实体字段上的安全投票者
我已经开始在我们的应用程序中做一些更高级的安全性工作,公司可以为每个模块创建自己的用户角色,使用可自定义的CRUD,这意味着您可以创建一个自定义角色“Users read only”,将“read”设置为“2”,并为用户模块创建、更新、删除为0。团队模块也是如此Symfony 不使用自定义子资源路径时关系实体字段上的安全投票者,symfony,api-platform.com,Symfony,Api Platform.com,我已经开始在我们的应用程序中做一些更高级的安全性工作,公司可以为每个模块创建自己的用户角色,使用可自定义的CRUD,这意味着您可以创建一个自定义角色“Users read only”,将“read”设置为“2”,并为用户模块创建、更新、删除为0。团队模块也是如此 0表示他根本没有访问权限 1表示可以访问公司下的所有数据 2意味着只能访问与他相关的东西(如果他是所有者 (另一个用户的) 这将导致这样一种行为,即当用户通过get请求请求团队时,它将返回团队中包含用户的团队,但是,由于用户角色配置
- 0表示他根本没有访问权限
- 1表示可以访问公司下的所有数据
- 2意味着只能访问与他相关的东西(如果他是所有者 (另一个用户的)
$capabilities[“users”][“read”]=2
,因此团队。用户
应该只包含他,而不包含其他团队成员,因为用户只能看到他自己和他创建的用户
到目前为止,我已经使用实现QueryCollectionExtensionInterface
并过滤出要返回给用户的结果的条令扩展来限制collection get操作:
- 当我使用具有
的角色进行查询时,集合只返回用户所属的团队或他创建的团队$capabilities[“teams”][“read”]=2
- 当我查询具有
角色的用户时,它将返回公司内的所有团队。这是正确的$capabilities[“teams”][“read”]=1
$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);
}
返回