管理面板配置
页面摘要:
/config/admin中的选项可用于调整管理面板的行为和服务器设置,包括自定义 URL、主机(host)和端口(port)。
/config/admin 文件用于定义 Strapi 应用程序的管理面板配置。
本页面充当 /config/admin 文件中所有配置参数和取值的参考,按主题分组。如需了解各功能的具体工作方式,请参阅每个小节开篇给出的链接。
管理面板行为
管理面板的行为可通过以下参数进行配置:
| Parameter | Description | Type | Default |
|---|---|---|---|
autoOpen | 启用或禁用启动时自动打开管理面板。 | boolean | true |
watchIgnoreFiles | 添加在开发期间不应被监听的自定义文件。 |
详见 此处(属性 ignored)。 | array(string) | [] |
| serveAdminPanel | 如果为 false,将不提供管理面板,且启动时不需要 auth.secret。
注意:index.html 仍会被提供。 | boolean | true |
管理面板的部分 UI 元素必须在 src/admin/app 文件中进行配置:
教程视频
要禁用包含教程视频的信息框,请将 config.tutorials 键设为 false。
发布通知
要禁用关于 Strapi 新版本发布的通知,请将 config.notifications.releases 键设为 false。
const config = {
// … other customization options go here
tutorials: false,
notifications: { releases: false },
};
export default {
config,
};
管理面板服务器
默认情况下,Strapi 的管理面板通过 http://localhost:1337/admin 访问。出于安全考虑,可以更新主机、端口和路径。
管理面板的服务器配置可通过以下参数进行:
| Parameter | Description | Type | Default |
|---|---|---|---|
url | 访问管理面板的路径。如果 URL 为相对路径,则会与服务器 URL 拼接。 |
例如:/dashboard 会使管理面板可通过 http://localhost:1337/dashboard 访问。 | string | /admin |
| host | 管理面板服务器的主机。 | string | localhost |
| port | 管理面板服务器的端口。 | string | 8000 |
如果你为 url 选项添加了一个路径,它不会为你的应用程序添加前缀。如需这样做,请使用 Nginx 等代理服务器(参见可选的软件部署指南)。
仅更新管理面板的路径
要使管理面板可通过另一个路径访问,例如 http://localhost:1337/dashboard,请定义或更新 url 属性:
module.exports = ({ env }) => ({
// … other configuration properties
url: "/dashboard",
});
自 Strapi 5.51 起,管理员身份验证 cookie 路径默认为 /admin,与 url 无关。更改 url 时,请同时将 auth.cookie.path 设置为相同值。否则管理面板无法读取自己的身份验证 cookie:登录请求成功,但其后的每个请求都会被拒绝,面板会在没有错误提示的情况下返回登录页。
module.exports = ({ env }) => ({
url: "/dashboard",
auth: {
cookie: {
path: "/dashboard", // must match url
},
},
});
更改 auth.cookie.path 后,在启动 Strapi 前重新构建管理面板,因为该值会在构建时内联到管理面板 bundle 中。
由于默认情况下后端服务器和管理面板服务器运行在相同的主机和端口上,只要你在后端服务器配置文件中未改动 host 和 port 属性值,仅更新 config/admin 文件即可生效。
更新管理面板的主机和端口
如果管理面板服务器和后端服务器没有托管在同一台服务器上,你需要更新管理面板的主机和端口。例如,要将管理面板托管在 my-host.com:3000:
JavaScript
module.exports = ({ env }) => ({
host: "my-host.com",
port: 3000,
// Additionally you can define another path instead of the default /admin one 👇
// url: '/dashboard'
});
TypeScript
export default ({ env }) => ({
host: "my-host.com",
port: 3000,
// Additionally you can define another path instead of the default /admin one 👇
// url: '/dashboard'
});
开发期间信任额外主机
当你运行 strapi develop 时,管理面板通过 Strapi 以中间件模式启动的 Vite 开发服务器提供,并通过 Koa 应用进行代理。默认情况下,Vite 会针对一小部分安全值校验 Host 请求头。不匹配的请求会被以 "Invalid Host" 响应拒绝,这导致你在通过隧道、反向代理或自定义域名访问管理面板时无法预览。Strapi 暴露了 Vite 的 server.allowedHosts 选项,以便在必要时扩展该允许列表。
Strapi 如何加载自定义 Vite 配置
开发期间 Strapi 会构建一个基础 Vite 配置,然后尝试从 ./src/admin/vite.config.{js,ts,mjs} 加载用户提供的配置。如果该文件导出一个函数,则会以基础配置作为参数调用它,Strapi 使用其返回值。项目模板附带了一个示例文件,它只是将一个自定义别名合并到所提供配置中,这是你自行覆盖时的良好起点。
允许额外主机
如果 ./src/admin/vite.config.ts(或 .js)尚不存在,则创建它并扩展开发服务器配置。以下示例片段在保持 Strapi 其余默认值不变的情况下添加了 2 个自定义域名:
JavaScript
import { mergeConfig } from 'vite';
export default (config) => {
return mergeConfig(config, {
server: {
allowedHosts: ['preview.my-app.test', '.example-proxy.internal'],
},
});
};
TypeScript
import { mergeConfig, type UserConfig } from 'vite';
export default (config: UserConfig) => {
return mergeConfig(config, {
server: {
allowedHosts: ['preview.my-app.test', '.example-proxy.internal'],
},
});
};
配置 allowedHosts 时的几个提示:
- 传入字符串数组或
'all',以匹配 Vite 接受的形态。 - 前导点(
.example.com)允许任何子域名。 - 当通过会重写端口的隧道访问管理面板时,请将此选项与 Strapi 现有的
hmr.clientPort设置结合使用。
保存文件后,重新启动 strapi develop。Vite 现在将信任 Host 请求头与你提供的条目匹配的请求,因此被代理或通过隧道访问的 URL 将正常加载,而不会触发主机校验错误。
部署在不同服务器上 {#deploy-on-different-servers}
除非你选择将 Strapi 的后端服务器和管理面板服务器部署在不同的服务器上,否则默认情况下:
- 后端服务器和管理面板服务器都运行在相同的主机和端口(
http://localhost:1337/)上 - 管理面板可通过
/admin路径访问,而后端服务器可通过/api路径访问
要将管理面板和后端部署在完全不同的服务器上,你需要同时配置服务器(/config/server)和管理面板(/config/admin-panel)的配置。
以下示例设置允许你从一个域名提供管理面板,而 API 运行在另一个域名上:
JavaScript
module.exports = ({ env }) => ({
host: env("HOST", "0.0.0.0"),
port: env.int("PORT", 1337),
url: "http://yourbackend.com",
});
module.exports = ({ env }) => ({
/**
* Note: The administration will be accessible from the root of the domain
* (ex: http://yourfrontend.com/)
*/
url: "/",
serveAdminPanel: false, // http://yourbackend.com will not serve any static admin files
});
TypeScript
export default ({ env }) => ({
host: env("HOST", "0.0.0.0"),
port: env.int("PORT", 1337),
url: "http://yourbackend.com",
});
export default ({ env }) => ({
/**
* Note: The administration will be accessible from the root of the domain
* (ex: http://yourfrontend.com/)
*/
url: "/",
serveAdminPanel: false, // http://yourbackend.com will not serve any static admin files
});
使用此配置:
- 管理面板可通过
http://yourfrontend.com访问 - 来自面板的所有 API 请求都将发送到
http://yourbackend.com - 由于
serveAdminPanel: false,后端服务器将不提供任何静态管理面板文件
API 令牌
API 令牌功能可通过以下参数进行配置:
| Parameter | Description | Type | Default |
|---|---|---|---|
apiToken.salt | 用于生成 API 令牌的盐(同时适用于 content-api 和 admin 两种令牌类型)。 | string | Random string |
apiToken.secrets.encryptionKey | 用于在管理面板中设置 API 令牌可见性的加密密钥。设置后,令牌密钥在任何时候都可被令牌所有者查看。 | string | Random string |
Admin tokens 是用于以编程方式访问管理面板功能的一种新型 API 令牌,完全通过管理面板进行配置。除以上参数外,不需要额外的基于代码的配置(参见 Admin tokens)。
审计日志
审计日志功能可通过以下参数进行配置:
| Parameter | Description | Type | Default |
|---|---|---|---|
auditLogs.enabled | 启用或禁用审计日志功能 | boolean | true |
auditLogs.retentionDays | 审计日志保留天数。 |
自托管用户与 Strapi Cloud 客户的行为不同,请参阅表下方的说明。 | integer | 90 |
| auditLogs.exportMaxRows | 单次 CSV 导出中包含的最大条目数 (v5.53+) | integer | 1000000 |
对于 Strapi Cloud 客户,将使用存储在许可证信息中的 auditLogs.retentionDays 值,除非在 config/admin.js|ts 配置文件中定义了_更小_的 retentionDays 值。
导出审计日志需要 read 和 export 审计日志权限。请在 Settings > Administration Panel > Roles 的审计日志部分授予这些权限。如果缺少任一权限,GET /admin/audit-logs/export 端点将返回 403。
身份验证
身份验证系统,包括 SSO 配置和会话管理,可通过以下参数进行配置:
基础身份验证
要配置基础身份验证,请使用以下参数:
| Parameter | Description | Type | Default |
|---|---|---|---|
auth | 身份验证配置 | object | - |
auth.secret | 用于编码 JWT 令牌的密钥。当 serveAdminPanel 为 true(默认值)时必填。以 serveAdminPanel: false 运行的纯 API 部署可以省略它。 | string | undefined |
auth.domain | 用于 SSO 身份验证的 cookie 中的域名 (Enterprise 计划) (SSO)) | string | undefined |
auth.providers | 用于 SSO 的身份验证提供方列表 | array(object) | - |
auth.options | 传递给 jsonwebtoken 的选项对象 | object | - |
auth.options.expiresIn | jsonwebtoken 中使用的 JWT 过期时间 | object | 30d |
auth.events | 为身份验证注册的所有事件订阅者的记录 | object | {} |
auth.events.onConnectionSuccess | 管理员用户成功登录管理面板时调用的函数 | function | undefined |
auth.events.onConnectionError | 管理员用户登录管理面板失败时调用的函数 | function | undefined |
会话管理还提供了额外的配置参数。
会话管理
默认情况下,管理员身份验证使用会话管理以增强安全性。
会话管理通过使用短生命周期访问令牌与较长生命周期刷新令牌配对,为 Strapi 应用程序中的身份验证提供了增强的安全性。这种方式降低了令牌被盗的风险,并允许对用户会话进行更精细的控制。
自 (vv5.24.0) 起,Strapi 将管理员身份验证数据存储在安全的、仅 HTTP 的 cookie 中。浏览器仅在 HTTPS 连接上接受并发送这些 cookie,因此尝试通过纯 HTTP 访问管理面板会导致会话 cookie 无法设置,从而导致登录失败。在生产环境中务必始终通过 HTTPS 暴露管理面板(例如,将 Strapi 置于 TLS 终止代理或负载均衡器之后)。本地开发在默认配置下仍可正常工作,因为在该环境中 cookie 不会被标记为安全。
Strapi 的会话管理系统同时支持通过用户与权限功能进行的管理面板身份验证和内容 API 身份验证。该系统提供:
- 用于 API 请求的短生命周期访问令牌(通常为 30 分钟)
- 用于获取新访问令牌的刷新令牌
- 用于定向登出的设备级会话
- 可针对不同安全需求配置的令牌生命周期
已过期的访问令牌不会结束管理员会话。在 Strapi (v5.54.0+) 中,闲置超过 accessTokenLifespan 的标签页会保持打开,保留任何未保存的工作,下一次请求会在用户无感知的情况下续期令牌。结束会话的是刷新窗口:下面的 idleSessionLifespan 和 maxSessionLifespan,或者从 Sessions 页面撤销的会话。管理面板仅在这些情况下以及用户登出时才会警告未保存的更改。
要配置会话生命周期和行为,请使用以下参数:
| Parameter | Description | Type | Default |
|---|---|---|---|
auth.sessions | 会话管理配置 | object | {} |
auth.sessions.accessTokenLifespan | 访问令牌生命周期(秒) | number | 1800 (30 minutes) |
auth.sessions.maxRefreshTokenLifespan | 最大刷新令牌生命周期(秒) | number | 2592000 (30 days, or legacy expiresIn value) |
auth.sessions.idleRefreshTokenLifespan | 闲置刷新令牌超时时间(秒) | number | 604800 (7 days) |
auth.sessions.maxSessionLifespan | 最大会话持续时间(秒) | number | 2592000 (30 days, or legacy expiresIn value) |
auth.sessions.idleSessionLifespan | 会话闲置超时时间(秒) | number | 3600 (1 hour) |
使用 create-strapi-app 脚手架创建的应用程序,在生成的 config/plugins.* 文件中默认已为「用户与权限」功能设置了 jwtManagement: 'refresh' 和 sessions.httpOnly: true。这使得内容 API 用户开箱即用地启用了基于刷新令牌、使用仅 HTTP 会话 cookie 的身份验证。
Cookie 配置
要配置用于管理员身份验证的 HTTP cookie,请使用以下参数:
| Parameter | Description | Type | Default |
|---|---|---|---|
auth.cookie | 管理员身份验证的 cookie 配置 | object | {} |
auth.cookie.name | 管理员访问令牌 cookie 的名称。该值会被裁剪并依据 RFC 6265 cookie 名称字符进行校验。无效值会回退到默认值。 | string | 'jwtToken' |
auth.cookie.domain | Cookie 域名(如未设置则继承自服务器) | string | undefined |
auth.cookie.path | Cookie 路径 | string | '/admin' |
auth.cookie.sameSite | SameSite cookie 属性 | string | 'lax' |
auth.cookie.secure | 是否在管理员身份验证 cookie 上设置 Secure 属性。未设置时,在生产环境的 HTTPS 上会自动启用;在生产环境中将其设为 false 会记录一条警告。 | boolean | undefined |
内容历史
内容历史功能可通过以下参数进行配置:
| Parameter | Description | Type | Default |
|---|---|---|---|
history.retentionDays | 历史版本保留天数。 |
该值只能缩短保留期,请参阅表下方的说明。 | integer | Defined by the license |
只有在 history.retentionDays 值_小于_许可证信息中存储的值时才会被采纳。它不能用于将历史版本的保留时间延长到超过许可证允许的范围。许可证在 Growth 套餐上设置 14 天的保留期,在 Enterprise 套餐上设置 30 天(可提升至最多 90 天)(参见 内容历史)。
功能标记
功能标记可通过以下参数进行配置:
| Parameter | Description | Type | Default |
|---|---|---|---|
flags | 用于开启或关闭管理面板中某些功能或元素的设置 | object | {} |
flags.nps | 启用/禁用净推荐值(NPS)弹窗 | boolean | true |
flags.promoteEE | 启用/禁用 Strapi Enterprise 功能的推广 | boolean | true |
flags.docLinks | 启用/禁用管理面板中显示的文档链接 | boolean | true |
忘记密码
忘记密码功能,包括邮件模板,可通过以下参数进行配置:
| Parameter | Description | Type | Default |
|---|---|---|---|
forgotPassword | 自定义忘记密码邮件的设置 | object | {} |
forgotPassword.emailTemplate | 邮件插件中定义的邮件模板 | object | Default template |
forgotPassword.from | 发件人邮件地址 | string | Default value defined in |
| your provider configuration | |||
forgotPassword.replyTo | 收件人被要求回复的默认地址或地址列表 | string | Default value defined in |
| your provider configuration | |||
forgotPassword.expiresIn | 密码重置令牌的生存时间(TTL)。接受以秒为单位的时长或简写字符串(例如 '15m'、'1h')。在此选项配置之前签发的令牌将被视为已过期并被拒绝。 | string | number | '1h' |
速率限制
管理面板身份验证端点的速率限制可通过以下参数进行配置。更多配置选项来自 koa2-ratelimit 包:
| Parameter | Description | Type | Default |
|---|---|---|---|
rateLimit | 自定义管理面板身份验证端点速率限制的设置 | object | {} |
rateLimit.enabled | 启用或禁用速率限制器 | boolean | true |
rateLimit.interval | 将请求视为同一速率限制桶的时间窗口 | object | { min: 5 } |
rateLimit.max | 时间窗口内允许的最大请求数 | integer | 5 |
rateLimit.delayAfter | 在延迟响应之前允许的请求数 | integer | 1 |
rateLimit.timeWait | 响应请求前的等待时间(毫秒) | integer | 3000 |
rateLimit.prefixKey | 速率限制键的前缀 | string | ${userEmail}:${ctx.request.path}:${ctx.request.ip} |
rateLimit.whitelist | 免于速率限制的 IP 地址数组 | array(string) | [] |
rateLimit.store | 速率限制的存储位置(Memory、Sequelize 或 Redis)。更多信息请参阅 koa2-ratelimit 文档 | object | MemoryStore |
Strapi AI (新增) {#strapi-ai}
Strapi AI 为内容类型构建器和媒体库添加了功能,适用于 (Growth 计划) 套餐,可以启用或禁用:
| Parameter | Description | Type | Default |
|---|---|---|---|
ai.enabled | 是否启用 Strapi AI | boolean | true |
传输令牌
数据传输功能的传输令牌可通过以下参数进行配置:
| Parameter | Description | Type | Default |
|---|---|---|---|
transfer.token.salt | 用于生成传输令牌的盐。 |
如果未定义传输令牌盐,传输功能将被禁用。 | string | a random string |
配置示例
/config/admin 文件至少应包含包含身份验证和 API 令牌所需参数的最小配置。也可以包含额外参数以构成完整配置。
环境配置(即使用 env() 辅助函数)无需包含所有值,只要它们存在于默认 /config/server 中即可。
Minimal configuration
默认配置创建于任何新项目,应至少包含以下内容:
JavaScript
module.exports = ({ env }) => ({
apiToken: {
salt: env('API_TOKEN_SALT', 'someRandomLongString'),
},
auditLogs: { // only accessible with an Enterprise plan
enabled: env.bool('AUDIT_LOGS_ENABLED', true),
},
auth: {
secret: env('ADMIN_JWT_SECRET', 'someSecretKey'),
},
transfer: {
token: {
salt: env('TRANSFER_TOKEN_SALT', 'anotherRandomLongString'),
}
},
});
TypeScript
export default ({ env }) => ({
apiToken: {
salt: env('API_TOKEN_SALT', 'someRandomLongString'),
},
auditLogs: { // only accessible with an Enterprise plan
enabled: env.bool('AUDIT_LOGS_ENABLED', true),
},
auth: {
secret: env('ADMIN_JWT_SECRET', 'someSecretKey'),
},
transfer: {
token: {
salt: env('TRANSFER_TOKEN_SALT', 'anotherRandomLongString'),
}
},
});
Full configuration
JavaScript
module.exports = ({ env }) => ({
apiToken: {
salt: env('API_TOKEN_SALT', 'someRandomLongString'),
secrets: {
encryptionKey: env('ENCRYPTION_KEY'),
},
},
ai: {
enabled: false, // use this to disable Strapi AI
},
auditLogs: { // only accessible with an Enterprise plan
enabled: env.bool('AUDIT_LOGS_ENABLED', true),
retentionDays: 120,
},
auth: {
events: {
onConnectionSuccess(e) {
console.log(e.user, e.provider);
},
onConnectionError(e) {
console.error(e.error, e.provider);
},
},
options: {
expiresIn: '7d',
},
secret: env('ADMIN_JWT_SECRET', 'someSecretKey'),
sessions: {
accessTokenLifespan: 1800, // 30 minutes
maxRefreshTokenLifespan: 2592000, // 30 days
idleRefreshTokenLifespan: 604800, // 7 days
maxSessionLifespan: 604800, // 7 days
idleSessionLifespan: 3600, // 1 hour
},
cookie: {
domain: env('ADMIN_COOKIE_DOMAIN'),
path: '/admin',
sameSite: 'lax',
},
},
history: { // only accessible with a Growth or Enterprise plan
retentionDays: 30,
},
url: env('PUBLIC_ADMIN_URL', '/dashboard'),
autoOpen: false,
watchIgnoreFiles: [
'./my-custom-folder', // Folder
'./scripts/someScript.sh', // File
],
host: 'localhost',
port: 8003,
serveAdminPanel: env.bool('SERVE_ADMIN', true),
forgotPassword: {
from: 'no-reply@example.com',
replyTo: 'no-reply@example.com',
},
rateLimit: {
interval: { hour: 1, min: 30 },
timeWait: 3*1000,
max: 10,
},
transfer: {
token: {
salt: env('TRANSFER_TOKEN_SALT', 'anotherRandomLongString'),
}
},
});
TypeScript
export default ({ env }) => ({
apiToken: {
salt: env('API_TOKEN_SALT', 'someRandomLongString'),
secrets: {
encryptionKey: env('ENCRYPTION_KEY'),
},
},
ai: {
enabled: false, // use this to disable Strapi AI
},
auditLogs: { // only accessible with an Enterprise plan
enabled: env.bool('AUDIT_LOGS_ENABLED', true),
retentionDays: 120,
},
auth: {
events: {
onConnectionSuccess(e) {
console.log(e.user, e.provider);
},
onConnectionError(e) {
console.error(e.error, e.provider);
},
},
options: {
expiresIn: '7d',
},
secret: env('ADMIN_JWT_SECRET', 'someSecretKey'),
sessions: {
accessTokenLifespan: 1800, // 30 minutes
maxRefreshTokenLifespan: 2592000, // 30 days
idleRefreshTokenLifespan: 604800, // 7 days
maxSessionLifespan: 604800, // 7 days
idleSessionLifespan: 3600, // 1 hour
},
cookie: {
domain: env('ADMIN_COOKIE_DOMAIN'),
path: '/admin',
sameSite: 'lax',
},
},
history: { // only accessible with a Growth or Enterprise plan
retentionDays: 30,
},
url: env('PUBLIC_ADMIN_URL', '/dashboard'),
autoOpen: false,
watchIgnoreFiles: [
'./my-custom-folder', // Folder
'./scripts/someScript.sh', // File
],
host: 'localhost',
port: 8003,
serveAdminPanel: env.bool('SERVE_ADMIN', true),
forgotPassword: {
from: 'no-reply@example.com',
replyTo: 'no-reply@example.com',
},
rateLimit: {
interval: { hour: 1, min: 30 },
timeWait: 3*1000,
max: 10,
},
transfer: {
token: {
salt: env('TRANSFER_TOKEN_SALT', 'anotherRandomLongString'),
}
},
});