由于我们重写 url 以使用 CI 的方式,您永远不会匹配您的 Apache 配置,因为您实际上是在请求index.php?{args}
. 如果要过滤,则必须在 CI 中进行。您的选择是核心控制器或挂钩。
一种简单的方法是创建一个您的管理/区域脚本扩展的核心控制器,并在那里检查 IP。
像这样的东西:
application/core/MY_Controller.php
:
class MY_Controller extends CI_Controller
{
public function __construct()
{
parent::__construct();
$this->load->config('permitted_ips');
// check visitor IP against $config['ips'] array, redirect as needed
}
}
然后,在您的“敏感”控制器中,扩展 MY_Controller:
application/controllers/admin/seekrit.php
class Seekrit extends MY_Controller
{
public function __construct() {
parent::__construct();
/* at this point any invalid IP has been redirected */
}
}
现在,如果您已经将核心控制器用于其他用途,只需$this->uri->segment()
在加载允许的 IP 配置文件并检查/重定向/死亡或您需要做的其他任何事情之前检查它们是否在受限区域。
此外,如果您不需要一个构造函数,则无需在管理控制器中使用构造函数,因为如果未定义父级将被构造。如果您定义一个,请务必致电父母。
您还可以将白名单放入数据库、Redis 等中。
另一种方法是使用钩子,特别是pre_controller
钩子。进入该挂钩时,所有安全类和基类都已运行。如果您想以更细化的方式保护部分或全部路由,这将是合适的。在那里,您可以定义一个包含路由的数组,例如:
$protected_routes = array(
'foo' => array(
'allow_ip' => '1.2.3.4',
'redirect_if_not' => site_url('goaway')
)
)
然后,在您的钩子类(或函数)中匹配第一段(我的示例只是一个函数):
$CI = get_instance();
$CI->load-config('my_hook');
$protected_routes = $CI->config->item('protected_routes');
$segment = $CI->uri->segment(1); // foo
if (in_array($segment, $protected_routes)) {
// grab $protected_routes[$segment] and work with it
}
这样做的好处是不会弄乱您的核心控制器,因为许多人使用它作为在方法之间共享代码的一种方式。但是,该挂钩将在每个请求上运行,这意味着将另外两个文件加载添加到引导程序。
我在大型 RESTful 服务上使用了 hook 方法,通过要求额外的标头来保护某些端点,并对其他端点实施不同类型的速率限制。请注意,上面的代码只是钩子中的一个示例,而不是如何设置钩子本身。阅读 CI 手册的 hooks 部分,它非常简单直接。
最后,如果你真的想通过 来做.htaccess
,你必须自己去请求。永远不会进入目录application/controllers/foo
,实际请求是/foo/controller/method{args}
,这会导致 CI 实例化foo/controller.php
类。请记住,一旦重写,服务器会看到index.php?....
为此,您可以根据请求 URI 模式重新编写,如下所示(尚未测试,YMMV):
RewriteRule (^|/)foo(/|$) - [F,L]
可用于将访问虚拟路径的任何人重定向到受保护的控制器。这可能更可取,因为它可以防止 PHP 需要处理它,但是您失去了对匹配时发生的事情的控制粒度。不过,如果您有多个敏感区域需要保护,您可以使用类似上述重写与钩子或核心实现相结合的方法。