diff --git a/docs/master/api-reference/directives.md b/docs/master/api-reference/directives.md index 1ec30095d5..15dd3c9267 100644 --- a/docs/master/api-reference/directives.md +++ b/docs/master/api-reference/directives.md @@ -476,6 +476,10 @@ directive @can( Additional arguments that are passed to `Gate::check`. """ args: [String!] + """ + Pass input variables as arguments that are passed to `Gate::check`. + """ + input: Boolean! ) on FIELD_DEFINITION ``` @@ -527,6 +531,15 @@ type Mutation { } ``` +You can pass the input variables as arguments to the policy setting `input` argument +```graphql +type Mutation { + createPost(input: PostInput): Post + @can(ability: "create", input: "true") +} +``` +Now you will have access to `PostInput` values in the policy + Starting from Laravel 5.7, [authorization of guest users](https://laravel.com/docs/authorization#guest-users) is supported. Because of this, Lighthouse does **not** validate that the user is authenticated before passing it along to the policy. diff --git a/src/Schema/Directives/CanDirective.php b/src/Schema/Directives/CanDirective.php index ca708a82e2..b668ee129b 100644 --- a/src/Schema/Directives/CanDirective.php +++ b/src/Schema/Directives/CanDirective.php @@ -21,6 +21,11 @@ class CanDirective extends BaseDirective implements FieldMiddleware, DefinedDire */ protected $gate; + /** + * @var array + */ + protected $args; + /** * CanDirective constructor. * @param \Illuminate\Contracts\Auth\Access\Gate $gate @@ -63,6 +68,11 @@ public static function definition(): string Additional arguments that are passed to `Gate::check`. """ args: [String!] + """ + Send input data as arguments to the policy. + Set false by default + """ + input: Boolean! ) on FIELD_DEFINITION SDL; } @@ -81,6 +91,7 @@ public function handleField(FieldValue $fieldValue, Closure $next): FieldValue return $next( $fieldValue->setResolver( function ($root, array $args, GraphQLContext $context, ResolveInfo $resolveInfo) use ($previousResolver) { + $this->args = $args; if ($find = $this->directiveArgValue('find')) { $modelOrModels = $resolveInfo ->argumentSet @@ -146,6 +157,9 @@ protected function authorize($user, $model): void */ protected function getAdditionalArguments(): array { - return (array) $this->directiveArgValue('args'); + $directiveArgs = (array) $this->directiveArgValue('args'); + $inputArgs = $this->directiveArgValue('input') === true ? [$this->args] : []; + return array_merge($directiveArgs, $inputArgs); } + } diff --git a/tests/Unit/Schema/Directives/CanDirectiveTest.php b/tests/Unit/Schema/Directives/CanDirectiveTest.php index 0144d43804..af386bf3ec 100644 --- a/tests/Unit/Schema/Directives/CanDirectiveTest.php +++ b/tests/Unit/Schema/Directives/CanDirectiveTest.php @@ -141,7 +141,7 @@ public function testProcessesTheArgsArgument(): void @can(ability: "dependingOnArg", args: [false]) @field(resolver: "'.$this->qualifyTestResolver('resolveUser').'") } - + type User { name: String } @@ -156,6 +156,41 @@ public function testProcessesTheArgsArgument(): void ')->assertErrorCategory(AuthorizationException::CATEGORY); } + public function testSendInputArgumentToPolicy(): void + { + $this->be(new User); + $this->schema = ' + type Query { + users(key1: String, key2: String, key3: String): [User]! + @can(ability:"severalArgs", input: true) + @field(resolver: "'.$this->qualifyTestResolver('resolveUser').'") + } + + type User { + name: String + } + '; + + $variables = [ + 'key1' => 'foo', + 'key2' => 'foo2', + 'key3' => 'foo3', + ]; + + $this->postGraphQL( + [ + 'operationName' => 'Users', + 'query' => 'query Users($key1: String, $key2: String, $key3: String) { + users(key1: $key1, key2: $key2, key3: $key3) { + name + } + } + ', + 'variables' => $variables, + ] + )->assertOk(); + } + public function resolveUser(): User { $user = new User; diff --git a/tests/Utils/Policies/UserPolicy.php b/tests/Utils/Policies/UserPolicy.php index 17a8474abb..069ec9712c 100644 --- a/tests/Utils/Policies/UserPolicy.php +++ b/tests/Utils/Policies/UserPolicy.php @@ -32,4 +32,9 @@ public function dependingOnArg($viewer, bool $pass): bool { return $pass; } + + public function severalArgs($user, array $input): bool + { + return $input['key1'] === 'foo' && $input['key2'] === 'foo2' && $input['key2'] === 'foo3'; + } }