A Collections / Globals Backed Payload RBAC Plugin
📖 Table of Contents
✨ Synopsis
- This plugin collects information from
collections
,globals
and user provided extrasynopses
to build a collection of unifiedfeatures
which looks like the following data structure:
{
feature: string, // the slug of a collection or a global
traits: string[], // a collection of field names or endpoint (which belongs to the collection or global) paths
verbs: string[], // create, read, update, delete
}[] // a collection of this of all the collections, globals and user provided synopses
- Then the data is used to bring to us this:
⚙️ Usage
yarn add payload-warding
# or
npm i payload-warding
// ...
import warding, { convention } from "payload-warding";
//...
export default buildConfig({
// ...
plugins: [
// ...
warding(
convention.opts({
root: { email: process.env.YOUR_ROOT_EMAIL!, password: process.env.YOUR_ROOT_PASSWORD! },
}),
),
// ...
],
// ...
});
// ...
The convention.opts
will merge your options with predefined default options, see convention.ts for details.
🎨 Options
root
/**
* The root user's email and password. If not provided, the root user will not
* be created.
*/
root?: {
email: string;
password: string;
};
Please note that the user created in the create-first-user
page will be automatically bound with a root
role. So it's fine to skip the root user creation.
user
/**
* The user {@link Options}.
*/
user?: Options;
type Options = {
slug: string;
fields?: Field[]; // payload's Field type
title?: string;
tag?: SpecLabels;
};
type SpecLabels = {
plural?: Record<string, string> | string;
singular?: Record<string, string> | string;
};
role
/**
* The role {@link Options}.
*/
role?: Options;
label
/**
* All the labels for plugin introduced collections, fields and select options.
*/
label?: Label;
ext
/**
* Extended features in the form of {@link Synopsis}s.
*/
ext?: Synopsis[];
type Synopsis = {
slug: string;
traits: [string, Label | undefined][];
label?: Label;
};
type Label = Record<string, string> | string;
This paired with the check
function in convention.ts can be used to build custom access control upon the user + role
system provided by this plugin.
mod
/**
* Modifies the {@link Built} result after {@link Warding.build}.
*/
mod?: (w: Built) => Built;
type Built = {
collections: { user: CollectionConfig; role: CollectionConfig };
warden: Warden;
populate: Populate;
initialize: Initialize;
initializationExtra?: { user: any; role: any };
};
See factory/spec.ts for details.
mute
/**
* Disable this plugin without uninstalling it.
*/
mute?: boolean;
🔐 Authorization
📚 Collections
Authorizations of Collections are provided by adding access
functions to all possible collections
, fields
...and so on. The said access
functions will ask for a specific feature
, traits
, verbs
combination to be present, or otherwise reject the operation it is assigned to.
For example, the expected feature
, traits
, verbs
combination for which an access.create
of a collection
chad will ask looks like this:
{
feature: "chad",
trais: [],
verbs: ["create"]
}
Any user who has a role
with a feature
chad and any trait
(which, if is left empty in the role editing page, will have a default "_" trait
assigned) of verb create can pass the check. As for the access.update
of a field
age of the collection
chad, it looks like this:
{
feature: "chad",
trais: ["age"],
verbs: ["update"]
}
🧭 Globals
Authorizations of Globals are provided the same way as Collections
🌠 Endpoints
Authorizations of Endpoints are provided by prepending check functions in the handler
function arrays. The check functions basically do the same as those access
functions mentioned above, in which case the verbs
are determined by the endpoint's http method as such:
{
post: "create",
connect: "read",
options: "read",
head: "read",
get: "read",
put: "update",
patch: "update",
delete: "delete",
}
✏️ Note
Note You can also choose to skip the authorization for specific
collections
,globals
or some of theirfields
orendpoints
by assign thecustom.warding.should
to false orcustom.warding.should.[verb]
flags of correspondingverbs
to false.
Alternatively, if an access function is customly assigned in
collections
,globals
orfields
, the authorization will always be skipped but a plugin generated authorization functionreq.context.warding
will be attached to the access function argument. So that plugin users can decide how and when to call the plugin generated authorization function.
The
custom.warding.should
andcustom.warding.should.[verb]
flags assigned infields
orendpoints
can override those assigned in their correspondingcollections
andglobals
.
The plugin generated authorization function
req.context.warding
will always be attached to the handler function's argument whenendpoints
have thecustom.warding.should
flag orcustom.warding.should.[verb]
flags assigned to false.