策略是在每个请求到达 控制器 之前对其执行特定逻辑的函数。它们主要用于保护业务逻辑。
Strapi 项目的每个 路由 都可以与一系列策略相关联。例如,名为“is-admin”的策略可以检查请求是否由管理员用户发送,并限制对关键路由的访问。
策略可以是全局的,也可以是局部的。全局策略 可以与项目中的任何路由相关联。局部策略仅适用于特定的 API 或 插件。
该图表示请求如何通过 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
}
policyContext
是 controller 上下文的包装器。它添加了一些逻辑,这些逻辑对于实现 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
要将策略应用于路由,请将其添加到其配置对象(请参阅 路由文档)。
策略的调用方式取决于其范围:
- 使用
global::policy-name
表示 全局策略 - 使用
api::api-name.policy-name
表示 API 策略 - 使用
plugin::plugin-name.policy-name
表示 插件策略
要列出所有可用策略,请运行 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']
}
}
]
}