我想保护内容类型的某些特定字段,以仅允许管理员用户修改值,但允许用户访问它。
想象一下User
类型和一个is_admin
字段。只有管理员应该能够更新它,但每个人都应该能够阅读它。
type User {
id: ID!
name: String!
email: String!
is_admin: Boolean!
}
can指令似乎不适用于突变字段。最初,我尝试添加带有自定义策略的@can(ability: "setAdmin")
,但没有任何效果。对突变“有效”使用相同的罐头/策略,但这还不够精细。</ p>
自定义字段限制using a custom directive似乎应该有所帮助,但这似乎在突变输入类型的字段级别上也不起作用。
type mutation {
updateUser(
input: UpdateUserInput! @spread
): User @update @middleware(checks: ["auth:api"])
}
input UpdateUserInput {
id: ID!
name: String!
email: String!
is_admin: Boolean! @adminOnly
}
在app/GraphQL/Directives/AdminOnlyDirective.php
中使用此自定义指令
<?php
namespace App\GraphQL\Directives;
use Closure;
use GraphQL\Type\Definition\ResolveInfo;
use Nuwave\Lighthouse\Exceptions\DefinitionException;
use Nuwave\Lighthouse\Schema\Directives\BaseDirective;
use Nuwave\Lighthouse\Schema\Values\FieldValue;
use Nuwave\Lighthouse\Support\Contracts\DefinedDirective;
use Nuwave\Lighthouse\Support\Contracts\FieldMiddleware;
use Nuwave\Lighthouse\Support\Contracts\GraphQLContext;
class AdminOnlyDirective extends BaseDirective implements FieldMiddleware, DefinedDirective
{
/**
* Name of the directive as used in the schema.
*
* @return string
*/
public function name(): string
{
return 'adminOnly';
}
public static function definition(): string
{
return /** @lang GraphQL */ <<<GRAPHQL
"""
Limit field update to only admin.
"""
directive @adminOnly() on FIELD_DEFINITION
GRAPHQL;
}
public function handleField(FieldValue $fieldValue, Closure $next): FieldValue
{
$originalResolver = $fieldValue->getResolver();
return $next(
$fieldValue->setResolver(
function ($root, array $args, GraphQLContext $context, ResolveInfo $resolveInfo) use ($originalResolver) {
$user = $context->user();
if (
// Unauthenticated users don't get to see anything
! $user
// The user's role has to match have the required role
|| !$user->is_admin
) {
return null;
}
return $originalResolver($root, $args, $context, $resolveInfo);
}
)
);
}
}
那么,有没有一种方法可以防止使用laravel灯塔“更新”特定字段?
答案 0 :(得分:1)
现在,您可以在插入数据库之前使用https://lighthouse-php.com/4.16/custom-directives/argument-directives.html#argtransformerdirective将该字段转换为from PIL import Image as PilImage
import io
import base64
import os
from .models import Image
class Images(View):
url = "images/select_image.html"
def get(self, request):
dir = <image file directory>
image_names = ['red', 'green', 'blue']
for image_name in image_names:
base_path = os.sep.join([dir, image_name])
path = '.'.join([base_path, 'png'])
pil_image = PilImage.open(path)
encoded_image = self._encode_image(pil_image)
Image.objects.get_or_create(name=image_name, image=encoded_image)
context = {'images': image_names}
return render(request, self.url, context)
@staticmethod
def _encode_image(image):
"""Return image encoded to base64 from a PIL.Image.Image."""
io_buffer = io.BytesIO()
image.save(io_buffer, format='PNG')
saved_image = io_buffer.getvalue()
encoded_image = ''.join(['data:image/jpg;base64,', base64.b64encode(saved_image).decode()])
return encoded_image
class DisplayImage(View):
url = "images/display_image.html"
def get(self, request, image_name):
image = get_object_or_404(Image, name=image_name)
context = {'image': image.image}
return render(request, self.url, context)
,或者抛出错误以避免对特定字段进行更改,就像@trim的行为一样; < / p>
在灯塔v5中,其类null
已重命名为ArgTransformerDirective
,方法ArgSanitizerDirective
已重命名为transform
https://github.com/nuwave/lighthouse/blob/v5.0-alpha.3/src/Schema/Directives/TrimDirective.php
额外:
我仍然在想@can的工作原理,因为我仍然需要删除整个属性,而不是将null传递给数据库;
更新:@仅适用于sanitize
类型而不是input
类型
答案 1 :(得分:0)
我在这里想到的第一个想法是创建两个不同的输入和/或突变。例如。对于有权访问该字段的管理员:
updateUserAsAdmin(
input: UpdateUserFullInput! @spread
): User @update
@middleware(checks: ["auth:api"])
@can("users.update.full")
UpdateUserFullInput
包含is_admin
字段。
我也多次遇到此讨论:https://github.com/nuwave/lighthouse/issues/325 也许您还可以在这里找到一些有用的想法。
您可能还需要查看官方文档:https://github.com/nuwave/lighthouse/blob/master/docs/master/security/authorization.md#custom-field-restrictions