如何在CodeIgniter中保护public文件夹内文件仅允许已登录用户访问
CodeIgniter public目录指定资源仅登录用户访问配置方案
核心原因:默认情况下Nginx/Apache会直接返回public目录下的静态文件,不会经过CodeIgniter的权限校验逻辑,所以需要调整配置让目标路径的请求走框架的权限校验流程。
方案1:保留目录位置,通过重写规则接入框架校验
步骤1:配置Web服务器重写规则
根据你使用的Web服务器选择对应配置:
- Nginx配置:在站点配置中添加如下规则,注意要放置在通用静态资源匹配规则之前,避免被覆盖
location ~ ^/(logs|code)/ { try_files $uri $uri/ /index.php?$query_string; }
- Apache配置:修改public目录下的
.htaccess文件,添加如下规则
RewriteEngine On RewriteRule ^(logs|code)/.*$ index.php [L]
步骤2:创建资源鉴权控制器
新建application/controllers/ProtectedAsset.php控制器,实现登录校验、路径安全校验和文件返回逻辑:
<?php defined('BASEPATH') OR exit('No direct script access allowed'); class ProtectedAsset extends CI_Controller { public function serve($type, $path) { // 替换为你项目自身的登录状态校验逻辑 if (!$this->session->userdata('is_login')) { show_error('无权访问', 403); } // 拼接真实文件路径,做路径安全校验防止路径遍历漏洞 $public_root = FCPATH; $full_path = realpath($public_root . $type . '/' . $path); $allowed_paths = [ realpath($public_root . 'logs/'), realpath($public_root . 'code/') ]; // 校验路径合法性 $valid = false; foreach ($allowed_paths as $allow_dir) { if (strpos($full_path, $allow_dir) === 0) { $valid = true; break; } } if (!$valid || !file_exists($full_path) || is_dir($full_path)) { show_404(); } // 返回文件内容,设置正确的响应头 $mime = get_mime_by_extension($full_path); header('Content-Type: ' . $mime); header('Content-Length: ' . filesize($full_path)); // 可选添加缓存头提升性能 // header('Cache-Control: public, max-age=86400'); readfile($full_path); exit; } }
步骤3:配置路由转发规则
打开application/config/routes.php,添加路由将目标路径请求转发到鉴权控制器:
$route['logs/(:any)'] = 'ProtectedAsset/serve/logs/$1'; $route['code/(:any)'] = 'ProtectedAsset/serve/code/$1';
方案2:移动敏感文件到非public目录(安全性更高)
从根源避免Web服务器直接泄露文件的风险,操作逻辑和方案1基本一致:
- 将
logs和code目录整体移动到和public同级的目录,不再放入public内 - 控制器中拼接文件路径时,将
FCPATH替换为APPPATH对应的上级目录路径即可 - 无需额外配置Web服务器重写规则,因为文件本身不在公开目录,所有访问必然走框架逻辑
注意事项
- 必须保留路径安全校验逻辑,避免攻击者构造
../类路径遍历请求,窃取项目敏感配置文件 - 若访问的文件体积较大,可按需添加缓存头、断点续传支持,降低PHP处理的性能开销
- 登录校验逻辑需和项目现有认证体系对齐,若使用第三方认证库(如ion_auth),替换为对应库的校验方法即可
内容的提问来源于stack exchange,提问作者Rovin Patwal
相关产品推荐
相关产品推荐

