PAYATHON 2026

CI4 如何为开发和生产环境分别配置 ContentSecurityPolicy.php?

数据阿明

CI4 不会仅凭 Config\development\ContentSecurityPolicy.php 和 Config\production\ContentSecurityPolicy.php 的存在,就自动按环境切换配置。可以在 app/Config/ContentSecurityPolicy.php 中根据 ENVIRONMENT 设置不同指令。如果要保留独立文件,需要在这个配置类中显式加载。

为什么分目录放置没有生效?

这种做法假设环境目录会自动覆盖配置,但 CI4 使用配置类,通常从 app/Config 获取配置,并通过环境变量覆盖相应属性。单独创建环境子目录不会让配置自动切换。CI4 配置说明

启用 CSP 后,响应对象会读取 app/Config/ContentSecurityPolicy.php 中的配置。因此,可以在该配置类中判断环境,也可以由它加载其他策略文件。CSP 配置说明

方案一:直接在配置类中判断环境

如果两套策略只有少量差异,可以在现有的 Config\ContentSecurityPolicy 类中添加下面的构造方法。保留文件中的其他配置属性;如果已有构造方法,就将逻辑合并进去。

public function __construct()
{
    $this->connectSrc = ['self'];

    if (ENVIRONMENT === 'development') {
        $this->connectSrc = [
            'self',
            'http://localhost:5173',
            'ws://localhost:5173',
        ];
    }

    parent::__construct();
}

这里假设开发环境需要连接 localhost:5173 上的 HTTP 服务和 WebSocket 服务。地址和端口仅作示例,应替换为项目实际使用的值;如果没有这些连接需求,就不要添加。

这段代码只调整 connect-src,其他指令继续使用现有配置。如果开发环境还需要从本地服务加载 JavaScript 或 CSS,也要分别调整 scriptSrc、styleSrc 等对应属性。

示例先设置环境默认值,再调用 parent::__construct()。这样 BaseConfig 可以完成初始化,匹配的环境变量也能随后覆盖默认值。构造方法中的执行顺序决定覆盖优先级。BaseConfig 实现

方案二:将策略保存在独立文件中

如果策略较多,可以保留一个配置类入口,将环境差异拆分到返回数组的 PHP 文件中。下面是自定义加载方式,目录名称不是 CI4 的特殊约定。

创建 app/Config/CSP/development.php:

<?php

return [
    'connectSrc' => [
        'self',
        'http://localhost:5173',
        'ws://localhost:5173',
    ],
];

创建 app/Config/CSP/production.php:

<?php

return [
    'connectSrc' => ['self'],
];

然后在现有的 app/Config/ContentSecurityPolicy.php 配置类中使用下面的构造方法,替换方案一的构造方法:

public function __construct()
{
    $file = ENVIRONMENT === 'development'
        ? 'development.php'
        : 'production.php';

    $policy = require __DIR__ . '/CSP/' . $file;

    $this->connectSrc = $policy['connectSrc'];

    parent::__construct();
}

这个示例只为 development 加载开发策略,其他环境使用生产策略。如果 testing 或自定义环境需要不同配置,应增加明确的映射。

两个拆分文件只返回配置数据,无须重复声明 Config\ContentSecurityPolicy 类。需要拆分更多指令时,可以在数组中添加对应字段,再在构造方法中赋给相应属性。

设置环境并确认生效

开发环境的项目根目录 .env 中设置:

CI_ENVIRONMENT = development

生产环境设置:

CI_ENVIRONMENT = production

应用运行时通过 ENVIRONMENT 常量获取当前环境。如果部署平台也设置了 CI_ENVIRONMENT,应确认实际运行值符合预期。环境配置说明

同时确认 app/Config/App.php 中已有的 $CSPEnabled 属性设置为 true,并保留项目原有的属性类型声明。启用 CSP

最后,在浏览器开发者工具的 Network 面板中打开页面请求,检查响应头中的 Content-Security-Policy。按上述示例配置且没有后续覆盖时,开发环境的 connect-src 应包含示例中的本地地址,生产环境应只包含 'self'。

如果实际响应头仍与配置不同,检查控制器、过滤器、Web 服务器或反向代理是否继续修改了 CSP。验证策略时还应留意 Debug Toolbar:官方文档说明它可能因 nonce 处理影响 CSP 响应头,必要时关闭后再检查。CSP 调试注意事项

备注:内容仅供参考。