策略 Policies

Strapi 策略是在每个请求到达控制器之前对其执行特定逻辑的函数。可以根据您的需求定制策略。

策略是在每个请求到达 控制器 之前对其执行特定逻辑的函数。它们主要用于保护业务逻辑。

Strapi 项目的每个 路由 都可以与一系列策略相关联。例如,名为“is-admin”的策略可以检查请求是否由管理员用户发送,并限制对关键路由的访问。

策略可以是全局的,也可以是局部的。全局策略 可以与项目中的任何路由相关联。局部策略仅适用于特定的 API插件

简化的 Strapi 后端图,其中突出显示了路由和策略 该图表示请求如何通过 Strapi 后端的简化版本,其中突出显示了策略和路由。后端定制介绍页面包含完整的交互式图表

实施

可以通过以下方式实施新策略:

  • 使用 交互式 CLI 命令 strapi generate
  • 或通过在相应文件夹中创建 JavaScript 文件手动实施(参见 项目结构):
  • ./src/policies/ 用于全局策略
  • ./src/api/[api-name]/policies/ 用于 API 策略
  • ./src/plugins/[plugin-name]/policies/ 用于插件策略

全局策略实施示例:

js
JavaScript
js
// ./src/policies/is-authenticated.js
module.exports = (policyContext, config, { strapi }) => {
  // 如果会话已打开转到下一个策略或到达控制器的操作
  if (policyContext.state.user) {
    return true
  }
  // 如果您未返回任何内容,Strapi 会认为您不想阻止该请求并会让它通过
  return false
}

policyContextcontroller 上下文的包装器。它添加了一些逻辑,这些逻辑对于实现 REST 和 GraphQL 的策略都很有用。


要查看路由策略的可能高级用法,请阅读后端自定义示例手册的 policies 页面。

可以使用 config 对象配置策略:

js
JavaScript
js
// .src/api/[api-name]/policies/my-policy.js
module.exports = (policyContext, config, { strapi }) => {
  // 如果用户的角色与配置中描述的角色相同
  if (policyContext.state.user.role.code === config.role) {
    return true
  }
  // 如果您没有返回任何内容,Strapi 会认为您不想阻止该请求并会让它通过
  return false
}

Usage

要将策略应用于路由,请将其添加到其配置对象(请参阅 路由文档)。

策略的调用方式取决于其范围:

要列出所有可用策略,请运行 yarn strapi strategies:list

全局策略

全局策略可以与项目中的任何路由关联。

js
JavaScript
js
// ./src/api/restaurant/routes/custom-restaurant.js
module.exports = {
  routes: [
    {
      method: 'GET',
      path: '/restaurants',
      handler: 'Restaurant.find',
      config: {
        /**
          在 Restaurant.js 控制器中执行 find 操作之前,
          我们调用全局“is-authenticated”策略,
          该策略位于 ./src/policies/is-authenticated.js。
         */
        policies: ['global::is-authenticated']
      }
    }
  ]
}

插件策略

插件 可以向应用程序添加和公开策略。例如,用户和权限插件 附带策略,以确保用户经过身份验证或有权执行操作:

js
JavaScript
js
// ./src/api/restaurant/routes/custom-restaurant.js
module.exports = {
  routes: [
    {
      method: 'GET',
      path: '/restaurants',
      handler: 'Restaurant.find',
      config: {
        /**
        `users-permissions` 插件提供的 `isAuthenticated`
        策略在 `Restaurant.js` 控制器中的 `find` 操作之前执行。
         */
        policies: ['plugin::users-permissions.isAuthenticated']
      }
    }
  ]
}

API 策略

API 策略与声明它们的 API 中定义的路由相关联。

ts
./src/api/restaurant/policies/is-admin.ts
ts
export default (policyContext, config, { strapi }) => {
  if (policyContext.state.user.role.name === 'Administrator') {
    // 转到下一个策略或者将到达控制器的操作。
    return true
  }

  return false
}

要在另一个 API 中使用策略,请使用以下语法引用它:api::[apiName].[policyName]

js
./src/api/category/routes/custom-category.js
js
module.exports = {
  routes: [
    {
      method: 'GET',
      path: '/categories',
      handler: 'Category.find',
      config: {
        /**
          The `is-admin` policy found at `./src/api/restaurant/policies/is-admin.js`
          is executed before the `find` action in the `Restaurant.js` controller.
         */
        policies: ['api::restaurant.is-admin']
      }
    }
  ]
}