用户
 找回密码
 入住 CI 中国社区
搜索
查看: 13952|回复: 24
收起左侧

[权限控制] 一个权限控制的思路,参考各位大神的,求评价

  [复制链接]
发表于 2012-3-28 17:07:55 | 显示全部楼层 |阅读模式
本帖最后由 Rabbit_52 于 2013-4-26 00:16 编辑

哈哈,话说一年之后来看这个帖子
权限控制的设计就是分面向模块和面向对象

更新:

前面参照别人的权限验证方法是对控制器和控制器的方法限制不同身份人的权限,但是这样就写死了,用户不能自由分配权限(比如说只允许粉丝看自己的帖子)

但是很多时候权限不是一条线的,从下到上权限递增,是有分支的,比如说bbs的某个会员对于一个版块来说是管理员,但对于另一个版块只是普通会员。

所以我判断是否有权限的思路是,将一个权限分支的权限控制做成数据表存到数据库,比如说有一个post_auth 表

QQ截图20120330115029.png

每条权限设置属于一个用户,首先找到请求权限的用户对于当前用户的身份,再同时传入操作去获取是否有该权限
/*
         *  guest 游客
         *  register 注册用户
         *  blocker 帖子主人黑名单
         *  friend 帖子主人朋友
         *  self 帖子主人
         *  admin 管理员
         */


相对于用户来说可能的请求者身份有如上,请求的操作可能有
QQ截图20120330115450.png

使用方法 就是在控制器中的某个需要权限验证的方法中调用一次权限验证方法(我是写了一个MY_Controller 包含一个 _auth() 方法 控制器继承MY_Controller )

PHP复制代码
require_once APPPATH . 'libraries/jiadb.php';
require_once APPPATH . 'libraries/auth.php';
require_once APPPATH . 'libraries/user.php';
        class MY_Controller extends CI_Controller {
                public $jiadb;
                function __construct() {
                        parent::__construct();
                        $this->jiadb = new Jiadb('users');
                }
               
                function _auth($option, $type, $param = '') {
                        $auth = Auth_factory::get_auth($option, $type, $param);
                        if(!$auth->access) {
                                show_error('No Right to Access');
                        }
                }
        }
复制代码


因为我的项目有三个权限分支(帖子,活动,社团)为了方便写了一个auth类,不同的分支的获取身份方法不一样

贴一个帖子权限嘛

PHP复制代码
class Auth {
                // 请求权限的用户
                public $request_user;
                // 请求的操作
                public $option;
                // 权限值
                public $access;
                public $jiadb;
                public $CI;
                function __construct($option) {
                        $this->access = 0;
                        $this->request_user = $this->CI->session->userdata('id');
                        $this->CI =& get_instance();
                        $this->jiadb = new Jiadb('options');
                        // option(name) => option(id)
                        $result = $this->jiadb->fetchAll(array('name' => $option));
                        $this->option = $result[0]['id'];
                }
               
                function get_access($owner_id, $identity, $table) {
                        $this->jiadb->_table = 'identity';
                        $result = $this->jiadb->fetchAll(array('name' => $identity));
                        $identity_id = $result[0]['id'];
                        $this->jiadb->_table = $table;
                        $result = $this->jiadb->fetchAll(array('user_id' => $owner_id, 'identity_id' => $identity_id, 'option' => $this->option));
                        $this->access = $result[0]['access'];
                }
        }
class Post_auth extends Auth {
                public $post;
                public $table;
                function __construct($option, $post = '') {
                        parent::__construct($option);
                        $this->post = $post;
                        $this->table = 'post_auth';
                }
               
                function get_access() {
                        $owner_id = $this->post['user_id'];
                        $identity = '';
                        // 游客
                        if($this->CI->session->userdata('type') == 'guest') {
                                $identity = 'guest';
                                parent::get_access($owner_id, $identity, $this->table);
                                if($this->access == 1) {
                                        return;
                                }
                        }
                        $owner = new User($owner_id);
                        // 黑名单
                        $blockers = $owner->get_blockers();
                        if(in_array($this->request_user, $friends)) {
                                $identity = 'blocker';
                                parent::get_access($owner_id, $identity, $this->table);
                                return;
                        }
                        // 注册用户
                        if($this->CI->session->userdata('type') == 'register') {
                                $identity = 'register';
                                parent::get_access($owner_id, $identity, $this->table);
                                if($this->access == 1) {
                                        return;
                                }
                        }
                        // 朋友
                        $friends = $owner->get_friends();
                        if(in_array($this->request_user, $friends)) {
                                $identity = 'friend';
                                parent::get_access($owner_id, $identity, $this->table);
                                if($this->access) {
                                        return;
                                }
                        }
                        $user = new User($this->request_user);
                        // 本人
                        if($this->post['user_id'] == $this->request_user) {
                                $identity = 'self';
                                parent::get_access($owner_id, $identity, $this->table);
                                if($this->access) {
                                        return;
                                }
                        }
                        // 验证是否管理员
                        if($this->CI->session->userdata('type') == 'admin') {
                                $this->access = 1;
                                return;
                        }
                }
        }
复制代码


个人感觉这样的代码不是很优雅~但是没得法,求各位大大提点意见
---------------------------------------------------------------------------
思路:
当需要执行需要权限验证的操作时,先通过hook判断对某个控制器的某个方法是否拥有权限(比如说管理员对所有帖子拥有编辑删除权限),再通过控制器内置方法对特定权限进行权限判断(比如说某个帖子的发帖者对它的帖子有编辑权限)

具体实现:
hook的pre_controller 挂钩点
全局变量 $RTR (CI 路由对象)能获取请求的控制器名以及方法名

Controller的 _remap($method, $param)
能获取请求的方法名以及所传参数,可以写一个MY_Controller 适当继承,根据不同情况适当重写

参考了帖子http://codeigniter.org.cn/forums/thread-4374-1-1.html


发表于 2012-3-28 17:12:34 | 显示全部楼层
hook是什么?
类似python里面的decorator那样的?
 楼主| 发表于 2012-3-28 17:14:21 | 显示全部楼层
thankwsx 发表于 2012-3-28 17:12
hook是什么?
类似python里面的decorator那样的?

hook就是CI的钩子嘛~
发表于 2012-4-6 11:48:05 | 显示全部楼层
可不可以共享一下唉 急需要 万分感谢楼主
 楼主| 发表于 2012-4-6 12:05:27 | 显示全部楼层
kuailewang 发表于 2012-4-6 11:48
可不可以共享一下唉 急需要 万分感谢楼主

现在项目还不是很完善,我放在google project上面的
https://code.google.com/p/jia2/
发表于 2012-4-10 10:54:00 | 显示全部楼层
Rabbit_52 发表于 2012-4-6 12:05
现在项目还不是很完善,我放在google project上面的
https://code.google.com/p/jia2/

谢谢
发表于 2012-4-10 11:02:16 | 显示全部楼层
Rabbit_52 发表于 2012-4-6 12:05
现在项目还不是很完善,我放在google project上面的
https://code.google.com/p/jia2/

require_once APPPATH . 'libraries/jiadb.php';
require_once APPPATH . 'libraries/auth.php';
require_once APPPATH . 'libraries/user.php';

这几个文件没有啊?
 楼主| 发表于 2012-4-11 09:15:53 | 显示全部楼层
kuailewang 发表于 2012-4-10 11:02
require_once APPPATH . 'libraries/jiadb.php';
require_once APPPATH . 'libraries/auth.php';
require ...

你checkout新版的呢,那个user是没有了,但是其他的都在libraries目录下
 楼主| 发表于 2012-4-12 10:47:27 | 显示全部楼层
heykite 发表于 2012-4-12 10:03
自从两个妓女自称是某名牌大学的毕业生后,我现在一般都自称文盲! 


哥们儿,你咋回事 =.=
发表于 2012-4-20 17:26:49 | 显示全部楼层
思路没错,我们开发系统也差不多类似的思路。

总得来说,可以分为URI的权限和细节权限。

URI的权限可以在pre_controller用钩子判断,而细节权限则要根据具体项目来做了,就像你说的,同一条URI,同一个人在不同的帖子面前,有时候只可以读,有时候即可读又可写。

本版积分规则