Skip to main content

如何为基于角色的访问控制 (RBAC) 创建自定义条件

🌐 How to create custom conditions for Role-Based Access Control (RBAC)

基于角色的访问控制(RBAC)是一种限制某些用户访问的方法。在 Strapi 应用中,管理员面板的用户是管理员。他们的角色和权限可以在管理员面板中配置

🌐 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

将单个条件声明为对象,将多个条件声明为对象数组。每个条件对象可以有5个可能的属性:

🌐 Declare a single condition as an object, and multiple conditions as an array of objects. Each condition object can have 5 possible properties:

  • displayName(字符串):在管理面板中显示的条件名称,
  • name (字符串):条件名称,使用连字符 ,
  • category(字符串,可选):条件可以分组到管理面板中提供的类别;如果未定义,条件将出现在“默认”类别下,
  • plugin(字符串,可选):如果条件是由插件创建的,应为插件的名称,使用kebab-case(例如 content-manager),
  • handler:用于验证条件的函数(参见 使用条件处理程序

/src/index.js 中找到的全局 bootstrap 函数 中声明并注册条件(参见 注册条件)。

🌐 Declare and register conditions in the global bootstrap function found in /src/index.js (see Registering conditions).

Note

条件 name 属性在其命名空间内充当唯一 ID,如果定义了 plugin 属性,则该命名空间是插件,否则就是根命名空间。

🌐 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

条件可以应用于任何权限,条件 handler 用于验证该条件。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.

查询对象用于验证你读取、创建、更新、删除或发布的实体的条件。它们使用 sift.js 库,但仅支持以下操作符:

  • $or
  • $and
  • $eq
  • $eqi
  • $ne
  • $in
  • $nin
  • $lt
  • $lte
  • $gt
  • $gte
  • $exists
  • $elemMatch

条件 handler 可以是一个同步或异步函数,该函数:

🌐 The condition handler can be a synchronous or asynchronous function that:

  • 接收发出请求的经过身份验证的用户,
  • 并返回 truefalse 或一个查询对象。

返回 truefalse 对于验证外部条件或经过身份验证的用户的条件是有用的。例如,一个允许仅在服务器时间为下午5点时访问管理面板页面的条件可以使用此处理程序:

🌐 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;

handler 函数接收已认证的用户,因此它可以对用户进行条件验证:

🌐 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');
},
};

为了获得更细粒度的控制,handler 函数也可以返回一个查询对象:

🌐 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

要在管理面板中可用,条件应在 /src/index 中找到的全局 bootstrap 函数 中声明并注册。使用 conditionProvider.register() 方法注册单个条件:

🌐 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:

/src/index.js

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 } },
});
};

要注册多个条件,将其定义为一个 条件对象数组,使用 conditionProvider.registerMany()

🌐 To register multiple conditions, defined as an array of condition objects, use conditionProvider.registerMany():

/src/index.js

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);
},
};