CodeIgniter使用Hooks进行访问权限的控制

背景

因为之前使用Express.js、Egg.js等框架,对中间件有着一定的印象。中间件是一个函数,它可以访问请求对象, 响应对象, 然后执行一些代码。

回到PHP,在 Laravel 等PHP框架中也是有中间件这个概念的。

初次使用CI,在想进行权限控制的时候,第一反应就是使用中间件,比如 /admin 必须需要登录且具有管理员权限才能访问,否则跳转到 /admin/login 进行登录。然后在CI的文档中并没有找到中间件,而是找到了Hooks。

启用钩子

钩子特性可以在 application/config/config.php 文件中全局的启用或禁用, 设置下面这个参数:

$config['enable_hooks'] = TRUE;

定义钩子

$hook['pre_controller'] = array(
    'class'    => 'MyClass',
    'function' => 'Myfunction',
    'filename' => 'Myclass.php',
    'filepath' => 'hooks',
    'params'   => array('beer', 'wine', 'snacks')
);
  • class 你希望调用的类名,如果你更喜欢使用过程式的函数的话,这一项可以留空。
  • function 你希望调用的方法或函数的名称。
  • filename 包含你的类或函数的文件名。
  • filepath 包含你的脚本文件的目录名。
  • params 你希望传递给你脚本的任何参数,可选。

挂钩点

  • pre_system 在系统执行的早期调用,这个时候只有 基准测试类 和 钩子类 被加载了, 还没有执行到路由或其他的流程。
  • pre_controller 在你的控制器调用之前执行,所有的基础类都已加载,路由和安全检查也已经完成。
  • post_controller_constructor 在你的控制器实例化之后立即执行,控制器的任何方法都还尚未调用。
  • post_controller 在你的控制器完全运行结束时执行。
  • display_override 覆盖 _display() 方法,该方法用于在系统执行结束时向浏览器发送最终的页面结果。 这可以让你有自己的显示页面的方法。注意你可能需要使用 $this->CI =& get_instance() 方法来获取 CI 超级对象,以及使用 $this->CI->output->get_output() 方法来 获取最终的显示数据。
  • cache_override 使用你自己的方法来替代 输出类 中的 _display_cache() 方法,这让你有自己的缓存显示机制。
  • post_system 在最终的页面发送到浏览器之后、在系统的最后期被调用。

Hooks挂钩点的选择

文档中并没有具体的代码说明Hooks类该怎么写。不过说白了,也就是在定义钩子时指明要调用的类和方法,重点在这个方法——也就是一个函数。当然也可以不用OOP的方法写,闭包也是OK的,具体可以看文档内容,这里没用到也就不赘述了。

关于想要进行权限控制的挂钩点的选择: pre_controllerpost_controller_constructor 是在路由函数执行之前调用,但是两者还是有区别的。CI中在自定义类里可以通过如下代码获取CI超级对象:

$CI =& get_instance();

起初我是使用 pre_controller 作为挂钩点,但是在希望获取CI超级对象时,得到的总是NULL,此时并没有理解文档中 在你的控制器调用之前执行 这句话。直到搜到 Codeigniter not loading CI super object 才直到什么问题:You cannot access the $CI instance in a pre_controller hook

使用 post_controller_constructor 挂钩点,此时Controller已经实例化,但是路由方法并没有被调用,可以获取 CI 对象,而此时也可以用CI的方法进行session的操作、数据库的操作等。

Hooks代码的编写

基本思路就是获取请求URL,然后判断此URL需不需要登录

获取URL并处理成数组:

$url = $_SERVER['PHP_SELF'];
    $urlArray = explode('/', $url);
    $urlArray = array_slice($urlArray, array_search('index.php', $urlArray) + 1, count($urlArray));

获取 CI 超级对象

private $CI;

function __construct()
{
    $this->CI =& get_instance();
}

比如我是对 $urlArray[0] 进行判断从而进行不同的处理,于是就用switch来完成:

switch ($urlArray[0]) {
    case 'admin':

        if ($this->CI->session->has_userdata('userid')) {
            ;
        } else {
            header("Location: /admin/login");
        }


        break;

    case 'user':

        if ($this->CI->session->has_userdata('userid')) {
            ;
        } else {
            header("Location: /user/login");
        }

        break;
    }

以上。供参考。

另一片可供参考的权限控制代码文章: http://abcdxyzk.github.io/blog/2012/04/03/tools-ci-access/

参考

钩子 - 扩展框架核心 Codeigniter not loading CI super object

我来评几句
登录后评论

已发表评论数()

相关站点

+订阅
热门文章