问题描述
我将 Symfony5
与 ApiPlaform
一起使用
我自然是这样设置 collectionoperations
:
* collectionoperations={
* "get"={
* "mehtod"="GET",* "security"="is_granted('LIST',object)",* "normalization_context"={"groups"={"user:list"}},* }
* },
并在我的选民中检查像这样的 supports
方法:
protected function supports($attribute,$subject): bool
{
return parent::supports($attribute,$subject)
&& (
$subject instanceof User
|| $this->arrayOf($subject,User::class)
);
}
我认为 arrayOf
条件会检查对象列表,但我收到了一个分页对象,因此只能检查它是否是一个分页对象,这可能会给我的其他选民带来问题。
无论如何,只需在 Paginator
方法中返回我的 VoteOnAttribute
对象(已经尝试过)
所以我的问题是,有没有办法通过将对象从注释发送给选民来检查对象列表上的授权?
谢谢!
解决方法
收集操作不会通过您的 User::class。 (它可能会像分页器一样通过……)
方法 1:过滤您的收藏
您可以通过更改用户的查询构建器来过滤您的集合。 见https://api-platform.com/docs/core/extensions/
方式 2:自定义规范化器
您可以在自定义规范器中检查安全性并更改 serialization_context
或在用户无权访问对象时抛出异常。这种方法会对性能产生负面影响。
这是我的规范化器的示例
标准化方法:
public function normalize($object,string $format = null,array $context = []): array
{
$context['groups'] = []; //remove all groups
$context['groups'][] = 'read:always';
if ($this->security->isGranted('ENTITY_ACCESS',$object)) {
$context['groups'][] = 'read'; //allow to read properties with @Groups{{"read"}}
} else {
throw new ClientError(ClientErrorType::CHECK_ACCESS,['type' => $this->getEntityName($object)]);
}
$context['groups'] = array_unique($context['groups']);
$context['resource_normalizer_call_data'][] = $object->getId();
return $this->normalizer->normalize($object,$format,$context);
}
支持归一化方法
public function supportsNormalization($data,array $context = []): bool
{
if ( //is object doctrine entity?
!$this->isEntity($this->managerRegistry->getManager(),$data)
|| !isset($context['graphql_operation_name'])
) {
return false;
}
if ( //dont normalize same entity twice!
isset($context['resource_normalizer_call_data'])
&& in_array($data->getId(),$context['resource_normalizer_call_data'])
) {
return false;
}
return true;
}
,
通过按如下方式检查查询结果的类型,我找到了一种适合我的解决方法:
protected function supports($attribute,$subject): bool
{
return parent::supports($attribute,$subject)
&& (
$subject instanceof User ||
$this->arrayOf($subject,User::class) ||
(is_a($subject,Paginator::class) &&
is_a(iterator_to_array($subject->getIterator())[0],User::class))
);
}