Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add injectArgs option to @can directive to pass along client defined arguments to the policy check #1043

Merged
merged 11 commits into from
Nov 14, 2019
13 changes: 13 additions & 0 deletions docs/master/api-reference/directives.md
Original file line number Diff line number Diff line change
Expand Up @@ -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!
faiverson marked this conversation as resolved.
Show resolved Hide resolved
spawnia marked this conversation as resolved.
Show resolved Hide resolved
) on FIELD_DEFINITION
```

Expand Down Expand Up @@ -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.

Expand Down
16 changes: 15 additions & 1 deletion src/Schema/Directives/CanDirective.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -63,6 +68,11 @@ public static function definition(): string
Additional arguments that are passed to `Gate::check`.
"""
args: [String!]
"""
faiverson marked this conversation as resolved.
Show resolved Hide resolved
Send input data as arguments to the policy.
Set false by default
"""
input: Boolean!
) on FIELD_DEFINITION
SDL;
}
Expand All @@ -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
Expand Down Expand Up @@ -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] : [];
spawnia marked this conversation as resolved.
Show resolved Hide resolved

return array_merge($directiveArgs, $inputArgs);
}
}
37 changes: 36 additions & 1 deletion tests/Unit/Schema/Directives/CanDirectiveTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ public function testProcessesTheArgsArgument(): void
@can(ability: "dependingOnArg", args: [false])
@field(resolver: "'.$this->qualifyTestResolver('resolveUser').'")
}

type User {
name: String
}
Expand All @@ -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]!
faiverson marked this conversation as resolved.
Show resolved Hide resolved
@can(ability:"severalArgs", input: true)
@field(resolver: "'.$this->qualifyTestResolver('resolveUser').'")
}

type User {
name: String
}
';

$variables = [
'key1' => 'foo',
'key2' => 'foo2',
'key3' => 'foo3',
];

$this->postGraphQL(
spawnia marked this conversation as resolved.
Show resolved Hide resolved
[
'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;
Expand Down
5 changes: 5 additions & 0 deletions tests/Utils/Policies/UserPolicy.php
Original file line number Diff line number Diff line change
Expand Up @@ -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';
faiverson marked this conversation as resolved.
Show resolved Hide resolved
}
}