You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CodeIgniter 3迁移至Nginx后,如何实现仅允许已登录用户访问指定文件目录

CodeIgniter 3迁移至Nginx后,如何实现仅允许已登录用户访问指定文件目录

兄弟,我完全懂你遇到的问题——把CI3从Apache迁到Nginx后,原本靠.htaccess做的权限控制直接失效了,未登录用户直接敲文件路径就能下载,你写的Nginx deny规则还不生效。这其实是Nginx的静态文件处理优先级导致的,咱们一步步来解决:

一、先搞懂为什么你的Nginx配置没生效

Nginx默认会优先处理真实存在的静态文件,也就是说,如果你的versoes或lgpd文件夹确实在网站根目录下,用户访问example.com.br/versoes/xyz.pdf时,Nginx会直接找到这个文件并返回,根本不会走你写的location /(versoes|lgpd)/规则。所以核心思路是:把这些文件请求先交给CodeIgniter做登录验证,再决定是否返回文件。

二、调整Nginx配置,让请求走CI路由

修改你的Nginx站点配置,把versoes和lgpd路径的请求转发到CI的入口文件index.php:

location ~ ^/(versoes|lgpd)/ {
    # 让Nginx不要直接处理静态文件,强制转发给CI处理
    try_files $uri $uri/ /index.php$request_uri;
}

这样不管文件是否存在,Nginx都会把请求交给CI,接下来就可以在CI里做权限校验了。

三、在CI里写一个权限验证+文件下载的控制器

创建一个Download.php控制器,专门处理文件下载的权限校验和文件输出:

<?php
defined('BASEPATH') OR exit('No direct script access allowed');

class Download extends CI_Controller {

    public function __construct() {
        parent::__construct();
        // 这里替换成你自己的登录校验逻辑
        // 比如检查session里的登录状态标记
        if (!$this->session->userdata('logged_in')) {
            // 未登录的话,要么返回403提示,要么跳转到登录页
            show_error('你没有权限访问该资源', 403);
            // 或者用 redirect('login'); 跳转到登录页面
            exit;
        }
    }

    // 处理文件下载请求
    public function serve($folder, $filename) {
        // 建议把文件存放在网站根目录以外的安全路径,比如/var/www/private_files/
        // 这里用FCPATH(CI的网站根目录常量)举例子,实际生产环境建议改更安全的路径
        $file_real_path = FCPATH . $folder . '/' . $filename;

        // 先检查文件是否存在且可读
        if (!file_exists($file_real_path) || !is_readable($file_real_path)) {
            show_error('请求的文件不存在或无法读取', 404);
            exit;
        }

        // 针对PDF文件设置响应头,让浏览器正确识别并触发下载
        header('Content-Type: application/pdf');
        header('Content-Disposition: attachment; filename="' . $filename . '"');
        header('Content-Length: ' . filesize($file_real_path));

        // 输出文件内容
        readfile($file_real_path);
        exit;
    }
}

四、配置CI路由,映射请求到控制器

打开application/config/routes.php,添加路由规则,把versoes和lgpd的请求指向刚才的控制器方法:

// 匹配versoes下的所有文件请求
$route['versoes/(:any)'] = 'download/serve/versoes/$1';
// 匹配lgpd下的所有文件请求
$route['lgpd/(:any)'] = 'download/serve/lgpd/$1';

五、进阶优化:用Nginx的X-Accel-Redirect提升下载效率

如果你的PDF文件比较大,用PHP的readfile可能会占用较多内存,推荐用Nginx的X-Accel-Redirect特性,让Nginx直接处理文件发送,减轻PHP的压力:

  1. 先把文件移到Nginx的内部访问路径,比如/var/www/private_files/,然后在Nginx配置里添加一个内部location:
location /private_files/ {
    internal; # 只允许内部请求访问,外部直接访问会返回404
    root /var/www;
}
  1. 修改CI控制器的serve方法:
public function serve($folder, $filename) {
    // 内部路径,对应Nginx里配置的/private_files/
    $internal_path = '/private_files/' . $folder . '/' . $filename;
    // 真实文件路径,用于检查文件是否存在
    $file_real_path = '/var/www/private_files/' . $folder . '/' . $filename;

    if (!file_exists($file_real_path) || !is_readable($file_real_path)) {
        show_error('请求的文件不存在或无法读取', 404);
        exit;
    }

    // 设置响应头,让Nginx接管文件发送
    header('Content-Type: application/pdf');
    header('Content-Disposition: attachment; filename="' . $filename . '"');
    header('X-Accel-Redirect: ' . $internal_path);
    exit;
}

这样配置后,只有登录用户才能通过CI的验证触发Nginx的文件发送,未登录用户直接访问文件路径会被Nginx拦截或者CI返回403,完美解决你的问题!

备注:内容来源于stack exchange,提问作者Zanellato

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.16 08:04:32