Skip to content

Commit

Permalink
inject input variables in policy through can directive
Browse files Browse the repository at this point in the history
  • Loading branch information
Fabian Torres committed Nov 12, 2019
1 parent b52e364 commit edc51c0
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 2 deletions.
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!
) 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!]
"""
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] : [];
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]!
@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;
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';
}
}

0 comments on commit edc51c0

Please sign in to comment.