我想根据模型策略中的视图方法过滤(不阻止访问)从我的 GraphQL API 返回的列表字段。
我已经编写了下面的指令,我已将其添加到我的架构中的字段中。
我有两个问题:
这不是实现我想要的结果的最佳方式,因为我必须注释我的模式中获取关系的每个字段。有一个更好的方法吗?
我在下面的解决方案有一个不起作用的边缘情况。返回过滤后的集合时,它不会加载架构中请求的对象上的嵌套字段。理想情况下,这将是递归的,对集合中的所有项目及其所有子字段使用相同的解析器。我怎样才能使这项工作?
class ViewPolicyFilterDirective extends BaseDirective implements FieldMiddleware {
/**
* Filters GraphQL list fields using Policies 'view' method
*
* @param \Nuwave\Lighthouse\Schema\Values\FieldValue $fieldValue
* @param \Closure $next
* @return \Nuwave\Lighthouse\Schema\Values\FieldValue
*/
public function handleField(FieldValue $fieldValue, Closure $next): FieldValue {
// Retrieve the existing resolver function
/** @var Closure $previousResolver */
$previousResolver = $fieldValue->getResolver();
// Wrap around the resolver
$wrappedResolver = function ($root, array $args, GraphQLContext $context, ResolveInfo $info) use ($previousResolver) {
// Call the resolver, passing along the resolver arguments
$result = $previousResolver($root, $args, $context, $info);
if ($result instanceof Collection && $result->count() > 0 && $result[0] instanceof Model) {
return $result->filter(function (Model $r) {
return Auth::user()->can('view', $r);
})->toArray();
} else if ($result instanceof Model && Auth::user()->can('view', $result)) {
return $result;
} else if ($result instanceof Model && !Auth::user()->can('view', $result)) {
throw new AuthorizationException(
"You are not authorized to access this"
);
}
return $result;
};
// Place the wrapped resolver back upon the FieldValue
// It is not resolved right now - we just prepare it
$fieldValue->setResolver($wrappedResolver);
// Keep the middleware chain going
return $next($fieldValue);
}
}