How to create custom conditions for Role-Based Access Control (RBAC)
Role-Based Access Control (RBAC) is an approach to restricting access to some users. In a Strapi application, users of the admin panel are administrators. Their roles and permissions are configured in the admin panel.
Declaring new conditions
Declare a single condition as an object, and multiple conditions as an array of objects. Each condition object can have 5 possible properties:
displayName
(string): the condition name as shown in the admin panel,name
(string): the condition name, kebab-cased,category
(string, optional): conditions can be grouped into categories available in the admin panel; if undefined, the condition will appear under the "Default" category,plugin
(string, optional): if the condition is created by a plugin, should be the plugin's name, kebab-cased (e.gcontent-manager
),handler
: a function used to verify the condition (see using the condition handler)
Declare and register conditions in the global bootstrap
function found in ./src/index.js
(see Registering conditions).
The condition name
property acts as a unique id within its namespace, that is either the plugin if the plugin
property is defined, or the root namespace.
Using the condition handler
A condition can be applied to any permission, and the condition handler
is used to verify the condition. The handler
is a function returning a query object or a boolean value.
Query objects are useful to verify conditions on the entities you read, create, update, delete or publish. They use the sift.js library, but only with the following supported operators:
$or
$and
$eq
$eqi
$ne
$in
$nin
$lt
$lte
$gt
$gte
$exists
$elemMatch
The condition handler
can be a synchronous or asynchronous function that:
- receives the authenticated user making the request,
- and returns
true
,false
, or a query object.
Returning true
or false
is useful to verify an external condition or a condition on the authenticated user.
For instance, a condition that allows access to a page in the admin panel only if server time is 5pm could use this handler:
handler: () => new Date().getHours() === 17;
The handler
function receives the authenticated user, so it can verify conditions on the user:
const condition = {
displayName: 'Email address from strapi.io',
name: 'email-strapi-dot-io',
async handler(user) {
return user.email.includes('@strapi.io');
},
};
For more granular control, the handler
function can also return a query object:
const condition = {
displayName: 'price greater than 50',
name: 'price-gt-50',
async handler(user) {
return { price: { $gt: 50 } };
},
};
Registering conditions
To be available in the admin panel, conditions should be declared and registered in the global bootstrap
function found in ./src/index
. Register a single condition with the conditionProvider.register()
method:
- JavaScript
- TypeScript
module.exports = async () => {
await strapi.admin.services.permission.conditionProvider.register({
displayName: 'Billing amount under 10K',
name: 'billing-amount-under-10k',
plugin: 'admin',
handler: { amount: { $lt: 10000 } },
});
};
export default async () => {
await strapi.admin.services.permission.conditionProvider.register({
displayName: 'Billing amount under 10K',
name: 'billing-amount-under-10k',
plugin: 'admin',
handler: { amount: { $lt: 10000 } },
});
};
To register multiple conditions, defined as an array of condition objects, use conditionProvider.registerMany()
:
- JavaScript
- TypeScript
const conditions = [
{
displayName: "Entity has same name as user",
name: "same-name-as-user",
plugin: "name of a plugin if created in a plugin",
handler: (user) => {
return { name: user.name };
},
},
{
displayName: "Email address from strapi.io",
name: "email-strapi-dot-io",
async handler(user) {
return user.email.includes('@strapi.io');
},
}
];
module.exports = {
async bootstrap(/*{ strapi }*/) {
// do your boostrap
await strapi.admin.services.permission.conditionProvider.registerMany(conditions);
},
};
// path: ./src/index.ts
const conditions = [
{
displayName: "Entity has same name as user",
name: "same-name-as-user",
plugin: "name of a plugin if created in a plugin"
handler: (user) => {
return { name: user.name };
},
},
{
displayName: "Email address from strapi.io",
name: "email-strapi-dot-io",
async handler(user) {
return user.email.includes('@strapi.io');
},
}
];
export default async () => {
// do your boostrap
await strapi.admin.services.permission.conditionProvider.registerMany(conditions);
};