From 0eb476916d487ff646625d9e8baff76c0116623d Mon Sep 17 00:00:00 2001 From: Maxime Rainville Date: Tue, 25 Feb 2020 18:36:31 +1300 Subject: [PATCH] DOC Explain how to implement a custom QueryPermissionChecker --- .../01_Verifying_CanView_Permission.md | 159 ++++++++++++++++++ .../02_Developer_Guides/19_GraphQL/index.md | 20 +++ 2 files changed, 179 insertions(+) create mode 100644 docs/en/02_Developer_Guides/19_GraphQL/01_Verifying_CanView_Permission.md create mode 100644 docs/en/02_Developer_Guides/19_GraphQL/index.md diff --git a/docs/en/02_Developer_Guides/19_GraphQL/01_Verifying_CanView_Permission.md b/docs/en/02_Developer_Guides/19_GraphQL/01_Verifying_CanView_Permission.md new file mode 100644 index 000000000..6c27b1982 --- /dev/null +++ b/docs/en/02_Developer_Guides/19_GraphQL/01_Verifying_CanView_Permission.md @@ -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 +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) diff --git a/docs/en/02_Developer_Guides/19_GraphQL/index.md b/docs/en/02_Developer_Guides/19_GraphQL/index.md new file mode 100644 index 000000000..217d1dfb7 --- /dev/null +++ b/docs/en/02_Developer_Guides/19_GraphQL/index.md @@ -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)