mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
DOC Explain how to implement a custom QueryPermissionChecker
This commit is contained in:
parent
cce2b16309
commit
0eb476916d
@ -0,0 +1,159 @@
|
|||||||
|
---
|
||||||
|
title: Controlling CanView access to DataObjects returned by GraphQL
|
||||||
|
summary: Your GraphQL service should honour the CanView permission when fetching DataObjects. Learn how to customise this access control check.
|
||||||
|
icon: cookie-bite
|
||||||
|
---
|
||||||
|
|
||||||
|
# Controlling who can view results in a GraphQL result set
|
||||||
|
|
||||||
|
The [Silverstripe ORM provides methods to control permissions on DataObject](Developer_Guides/Model/Permissions). In
|
||||||
|
most cases, you'll want to extend this permission model to any GraphQL service you implement that returns a DataObject.
|
||||||
|
|
||||||
|
## The QueryPermissionChecker interface
|
||||||
|
|
||||||
|
The GraphQL module includes a `QueryPermissionChecker` interface. This interface can be used to specify how GraphQL
|
||||||
|
services should validate that users have access to the DataObjects they are requesting.
|
||||||
|
|
||||||
|
The default implementation of `QueryPermissionChecker` is `CanViewPermissionChecker`. `CanViewPermissionChecker` directly calls the `CanView` method of each DataObject in your result set and filters out the entries not visible to the current user.
|
||||||
|
|
||||||
|
Out of the box, the `CanView` permission of your DataObjects are honoured when Scaffolding GraphQL queries.
|
||||||
|
|
||||||
|
## Customising how the results are filtered
|
||||||
|
|
||||||
|
`CanViewPermissionChecker` has some limitations. It's rather simplistic and will load each entry in your results set to perform a CanView call on it. It will also convert the results set to an `ArrayList` which can be inconvenient if you need to alter the underlying query after the _CanView_ check.
|
||||||
|
|
||||||
|
Depending on your exact use case, you may want to implement your own `QueryPermissionChecker` instead of relying
|
||||||
|
on `CanViewPermissionChecker`.
|
||||||
|
|
||||||
|
Some of the reasons you might consider this are:
|
||||||
|
* the access permissions on your GraphQL service differ from the ones implemented directly on your DataObject
|
||||||
|
* you want to speed up your request by filtering out results the user doesn't have access to directly in the query
|
||||||
|
* you would rather have a `DataList` be returned.
|
||||||
|
|
||||||
|
### Implementing your own QueryPermissionChecker class
|
||||||
|
|
||||||
|
The `QueryPermissionChecker` requires your class to implement two methods:
|
||||||
|
* `applyToList` which filters a `Filterable` list based on whether a provided `Member` can view the results
|
||||||
|
* `checkItem` which checks if a provided object can be viewed by a specific `Member`.
|
||||||
|
|
||||||
|
#### Filtering results based on the user's permissions
|
||||||
|
|
||||||
|
In some context, whether a user can view an object is entirely determined on their permissions. When that's the
|
||||||
|
case, you don't even need to get results to know if the user will be able to see them or not.
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
use SilverStripe\GraphQL\Permission\QueryPermissionChecker;
|
||||||
|
use SilverStripe\ORM\ArrayList;
|
||||||
|
use SilverStripe\ORM\Filterable;
|
||||||
|
use SilverStripe\Security\Member;
|
||||||
|
use SilverStripe\Security\Permission;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This implementation assumes that only users with the ADMIN permission can view results.
|
||||||
|
*/
|
||||||
|
class AdminPermissionChecker implements QueryPermissionChecker
|
||||||
|
{
|
||||||
|
|
||||||
|
public function applyToList(Filterable $list, Member $member = null)
|
||||||
|
{
|
||||||
|
return Permission::check('ADMIN', 'any', $member) ?
|
||||||
|
$list :
|
||||||
|
ArrayList::create([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function checkItem($item, Member $member = null)
|
||||||
|
{
|
||||||
|
return Permission::check('ADMIN', 'any', $member);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Filtering results based on the user's permissions
|
||||||
|
|
||||||
|
Some times, whether a user can view an object is determined by some information on the record. If that's the case,
|
||||||
|
you can filter out results the user can not see by altering the query. This has some performance advantage, because
|
||||||
|
the results are filtered directly by the query.
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
use SilverStripe\GraphQL\Permission\QueryPermissionChecker;
|
||||||
|
use SilverStripe\ORM\Filterable;
|
||||||
|
use SilverStripe\Security\Member;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This implementation assumes that the results are assigned an owner and that only the owner can view a record.
|
||||||
|
*/
|
||||||
|
class OwnerPermissionChecker implements QueryPermissionChecker
|
||||||
|
{
|
||||||
|
|
||||||
|
public function applyToList(Filterable $list, Member $member = null)
|
||||||
|
{
|
||||||
|
return $list->filter('OwnerID', $member ? $member->ID : -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function checkItem($item, Member $member = null)
|
||||||
|
{
|
||||||
|
return $member && $item->OwnerID === $member->ID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Using a custom QueryPermissionChecker implementation
|
||||||
|
|
||||||
|
There's three classes that expect a `QueryPermissionChecker`:
|
||||||
|
* `SilverStripe\GraphQL\Scaffolding\Scaffolders\ItemQueryScaffolder`
|
||||||
|
* `SilverStripe\GraphQL\Scaffolding\Scaffolders\ListQueryScaffolder`
|
||||||
|
* `SilverStripe\GraphQL\Pagination\Connection`
|
||||||
|
|
||||||
|
Those classes all implement the `SilverStripe\GraphQL\Permission\PermissionCheckerAware` and receive the default
|
||||||
|
`QueryPermissionChecker` from the Injector. They also have a `setPermissionChecker` method that can be use to provide a custom `QueryPermissionChecker`.
|
||||||
|
|
||||||
|
#### Scaffolding types with a custom QueryPermissionChecker implementation
|
||||||
|
|
||||||
|
There's not any elegant way of defining a custom `QueryPermissionChecker` when scaffolding types at this time. If
|
||||||
|
you need the ability to use a custom `QueryPermissionChecker`, you'll have to build your query manually.
|
||||||
|
|
||||||
|
#### Overriding the QueryPermissionChecker for a class extending ListQueryScaffolder
|
||||||
|
|
||||||
|
If you've created a GraphQL query by creating a subclass of `ListQueryScaffolder`, you can use the injector to
|
||||||
|
override `QueryPermissionChecker`.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
---
|
||||||
|
Name: custom-graphqlconfig
|
||||||
|
After: graphqlconfig
|
||||||
|
---
|
||||||
|
SilverStripe\Core\Injector\Injector:
|
||||||
|
SilverStripe\GraphQL\Permission\QueryPermissionChecker.my-custom:
|
||||||
|
class: App\Project\CustomQueryPermissionChecker
|
||||||
|
App\Project\CustomListQueryScaffolder:
|
||||||
|
properties:
|
||||||
|
permissionChecker: '%$SilverStripe\GraphQL\Permission\QueryPermissionChecker.my-custom'
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Manually specifying a QueryPermissionChecker on a Connection
|
||||||
|
|
||||||
|
If you're manually instantiating an instance of `SilverStripe\GraphQL\Pagination\Connection` to resolve your results,
|
||||||
|
you can pass an instance of your own custom `QueryPermissionChecker`.
|
||||||
|
|
||||||
|
```php
|
||||||
|
$childrenConnection = Connection::create('Children')
|
||||||
|
->setConnectionType($this->manager->getType('Children'))
|
||||||
|
->setSortableFields([
|
||||||
|
'id' => 'ID',
|
||||||
|
'title' => 'Title',
|
||||||
|
'created' => 'Created',
|
||||||
|
'lastEdited' => 'LastEdited',
|
||||||
|
])
|
||||||
|
->setPermissionChecker(new CustomQueryPermissionChecker());
|
||||||
|
```
|
||||||
|
|
||||||
|
## API Documentation
|
||||||
|
|
||||||
|
* [CanViewPermissionChecker](api:SilverStripe\GraphQL\Permission\CanViewPermissionChecker)
|
||||||
|
* [Connection](api:SilverStripe\GraphQL\Pagination\Connection)
|
||||||
|
* [ItemQueryScaffolder](api:SilverStripe\GraphQL\Scaffolding\Scaffolders\ItemQueryScaffolder)
|
||||||
|
* [ListQueryScaffolder](api:SilverStripe\GraphQL\Scaffolding\Scaffolders\ListQueryScaffolder)
|
||||||
|
* [PermissionCheckerAware](api:SilverStripe\GraphQL\Permission\PermissionCheckerAware)
|
||||||
|
* [QueryPermissionChecker](api:SilverStripe\GraphQL\Permission\QueryPermissionChecker)
|
20
docs/en/02_Developer_Guides/19_GraphQL/index.md
Normal file
20
docs/en/02_Developer_Guides/19_GraphQL/index.md
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
title: GraphQL
|
||||||
|
summary: Learn how to create and customise GraphQL services on your Silverstripe CMS project.
|
||||||
|
introduction: Learn how to create and customise GraphQL services on your Silverstripe CMS project.
|
||||||
|
icon: cookie
|
||||||
|
---
|
||||||
|
|
||||||
|
[CHILDREN]
|
||||||
|
|
||||||
|
## Additional documentation
|
||||||
|
|
||||||
|
A substantial part of the GraphQL documentation for Silverstripe CMS still
|
||||||
|
reside on the GraphQL module's _Readme_ file. We are in the process of folding
|
||||||
|
this information back into the main Silverstripe CMS documentation.
|
||||||
|
|
||||||
|
* [silverstripe/graphql](https://github.com/silverstripe/silverstripe-graphql/)
|
||||||
|
|
||||||
|
## API Documentation
|
||||||
|
|
||||||
|
* [GraphQL](api:SilverStripe\GraphQL)
|
Loading…
Reference in New Issue
Block a user