CI框架下权限管理,角色组,权限菜单最佳实践

在后台开发中,对管理员的权限组(角色)的管理,以及对应的菜单按权限加载是基本的需求,之前基于TP5框架参考Auth类在上一家公司将这套系实践上线,目前由于更换工作,新公司使用的是CI框架,后台的这个需求依然存在,于是在CI上又实践一次,记录一下。
CI框架权限管理

预期

这套简易的权限系统达到的预期效果:对每个管理员可以指定多个角色,每个角色分配不同的权限,权限对应每个控制器的每个对外调用的方法,菜单的跳转与权限挂钩,后台菜单根据管理员拥有的权限来加载,从而实现管理员=>多角色=>权限=>菜单的后台权限菜单管理系统。

环境:CodeIgniter 3.1.9 + PHP 7.2 + MariaDB 10.1.36

数据表:

管理员表:

CREATE TABLE `admin` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
  `username` varchar(100) NOT NULL DEFAULT '' COMMENT '用户名',
  `password` varchar(100) NOT NULL DEFAULT '' COMMENT '密码',
  `status` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '状态',
  `createtime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '添加时间',
  `updatetime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '更新时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uniq_username` (`username`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='管理员表';

权限表:

CREATE TABLE `auth_rule` (
  `name` varchar(200) NOT NULL DEFAULT '' COMMENT '验证规则',
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `title` varchar(200) DEFAULT '' COMMENT '权限名称',
  `status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '1正常0关闭',
  `cat_id` tinyint(2) NOT NULL DEFAULT '1' COMMENT '权限分类',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='权限表';

权限分类表:

CREATE TABLE `auth_rule_cat` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `title` varchar(200) DEFAULT '' COMMENT '权限分类名称',
  `status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '1正常0删除',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='权限分类表';

角色组表:

CREATE TABLE `et_auth_group` (
  `id` int(4) unsigned NOT NULL AUTO_INCREMENT,
  `title` varchar(200) NOT NULL DEFAULT '' COMMENT '角色名',
  `status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '1正常0禁用',
  `rules` text NOT NULL COMMENT '权限id,英文逗号间隔',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='角色组';

用户角色关系表:

CREATE TABLE `auth_group_access` (
  `uid` int(10) unsigned NOT NULL COMMENT '管理员id',
  `group_id` int(10) unsigned NOT NULL COMMENT '角色组id'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户角色关系表';

后台菜单表:

CREATE TABLE `et_auth_menu` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `icon` varchar(50) DEFAULT '' COMMENT '菜单字体图标icon',
  `title` varchar(100) NOT NULL DEFAULT '' COMMENT '菜单的中文名称',
  `rule_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '对应的权限id',
  `pid` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '菜单pid所属分类父级id,0表示顶级',
  `url` varchar(100) DEFAULT '' COMMENT '菜单对应的uri',
  `et_order` int(10) unsigned NOT NULL DEFAULT '1' COMMENT '排序',
  `status` tinyint(2) NOT NULL DEFAULT '1' COMMENT '1正常0删除',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='后台菜单';

实现

对应数据表的增删改查就是基本的条件,这里只讲一下权限验证以及菜单加载的实现。

添加需要验证的权限:

权限列表
这里需要将每个控制器里对外开放的方法都当作规则添加进来。

封装验证类

libraries/common下添加文件Authhandler.php,代码:

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

/**
 * 权限验证
 * hsu1943 20181112
 */
class Authhandler
{
    protected _CI;

    // 默认配置
    public_config = array(
        'AUTH_ON'               =>  true,       // 验证开关
        'SUPER_ADMINISTRATOR'   =>  'admin',    // 超级管理员用户名
    );

    public function __construct()
    {
        this->_CI =& get_instance();
    }

    /**
     * 权限验证
     * @param  intuid        用户id
     * @param  array        names      待验证的权限,支持逗号分隔的权限规则或索引数组
     * @param  stringrelation   待验证权限是否都需要满足,'or'|'and'
     * @return boolean                  true|false
     */
    public function check(uid,names, relation = 'or')
    {
        // 关闭验证跳过
        if (!this->_config['AUTH_ON']) {
            return true;
        }

        // 超管跳过
        if(_SESSION['admin']['username'] ===this->_config['SUPER_ADMINISTRATOR'])
        {
            return true;
        }

        // 获取用户权限
        authList =this->getAuthList(uid);

        // 待验证权限
        if (is_string(names)) {
            names = strtolower(names);
            if (strpos(names, ',') !== false) {names = explode(',', names);
            } else {names = array(names);
            }
        }

        // 通过验证的权限数组list = [];
        foreach (names asname) {
            if(in_array(name,authList))
            {
                list[] =name;
            }
        }

        if ('or' == relation and !empty(list)) {
            return true;
        }
        diff = array_diff(names, list);
        if ('and' ==relation and empty(diff)) {
            return true;
        }
        return false;
    }

    /**
     * 获取用户所有角色组下的权限name集合
     * @param  intuid        管理员id
     * @return array    authList   权限name集合
     */
    public function getAuthList(uid)
    {
        this->_CI->load->library('mysql/authdb');groups = this->_CI->authdb->getGroupsByUID(uid);

        ids = [];
        foreach (groups as g) {ids = array_merge(ids, explode(',', trim(g['rules'], ',')));
        }
        ids = array_unique(ids);
        rules =this->_CI->authdb->getRulesByIds(ids);_SESSION['admin']['AUTH_'.uid] =rules;
        authList = array_column(rules, 'name');
        return $authList;
    }
}

公共代码中添加验证

这里的公共代码在CI框架中有多重选择,比如post_controller_constructor钩子中验证,或者控制器的核心父类core/MY_admin_controller.php中。

我选择在后者,在公共父类中验证用户SESSION通过后做验证:

// 验证权限
    url_name = 'admin/' .this->router->fetch_class() . '/' . this->router->fetch_method();this->load->library('common/authhandler');
    check =this->authhandler->check(_SESSION['admin']['id'],url_name);
    if(!$check){
        show_error('Sorry, Permission denied!');
    }

添加权限菜单

添加进来的权限菜单类似这样的:
根据权限加载菜单
菜单对应的跳转URL实际上跟权限中的规则是一一对应的,根据这个可以检索到对应的权限与菜单绑定。

根据用户权限加载对应菜单

用户登录成功,查询用户对应权限组,合并权限组拥有的权限,去重后得到该用户所拥有的全部权限,根据权限查询对应的菜单,然后在模版公共模块中循环加载出来就行了。

CI框架下权限管理,角色组,权限菜单最佳实践

原文链接:https://beltxman.com/2193.html,若无特殊说明本站内容为 行星带 原创,未经同意禁止转载。

CI框架下权限管理,角色组,权限菜单最佳实践”上有 2 条评论;

评论已关闭。

Scroll to top