欢迎光临
我们一直在努力

thinkcmf权限管理系统

在ThinkPHP中有两种权限管理系统!

一种是 Auth,一种是 RBAC。同学你会说,这都是什么东西?它们会有什么区别呢?

答:目前我所知道的概念是这样的:Auth是1个用户可以有多个角色,RBAC是1个用户有1个角色。这里权限张伟用文档做了全部的解释!

[TOC]

1.相关表结构

  • users 用户表(管理员身份)
  • role 角色表
DROP TABLE IF EXISTS `cmf_role`;
CREATE TABLE `cmf_role` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `parent_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '父角色ID',
  `status` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '状态;0:禁用;1:正常',
  `create_time` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
  `update_time` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '更新时间',
  `list_order` float NOT NULL DEFAULT '0' COMMENT '排序',
  `name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '角色名称',
  `remark` varchar(255) NOT NULL DEFAULT '' COMMENT '备注',
  PRIMARY KEY (`id`),
  KEY `parentId` (`parent_id`),
  KEY `status` (`status`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COMMENT='角色表';

  • role_user 角色所在的用户
DROP TABLE IF EXISTS `cmf_role_user`;
CREATE TABLE `cmf_role_user` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `role_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '角色 id',
  `user_id` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '用户id',
  PRIMARY KEY (`id`),
  KEY `group_id` (`role_id`),
  KEY `user_id` (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='用户角色对应表';
  • auth_access 用户菜单授权记录表
DROP TABLE IF EXISTS `cmf_auth_access`;
CREATE TABLE `cmf_auth_access` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `role_id` int(10) unsigned NOT NULL COMMENT '角色',
  `rule_name` varchar(100) NOT NULL DEFAULT '' COMMENT '规则唯一英文标识,全小写',
  `type` varchar(30) NOT NULL DEFAULT '' COMMENT '权限规则分类,请加应用前缀,如admin_',
  PRIMARY KEY (`id`),
  KEY `role_id` (`role_id`),
  KEY `rule_name` (`rule_name`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='权限授权表';
  • auth_role 访问规则表
DROP TABLE IF EXISTS `cmf_auth_rule`;
CREATE TABLE `cmf_auth_rule` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '规则id,自增主键',
  `status` tinyint(3) unsigned NOT NULL DEFAULT '1' COMMENT '是否有效(0:无效,1:有效)',
  `app` varchar(15) NOT NULL COMMENT '规则所属module',
  `type` varchar(30) NOT NULL DEFAULT '' COMMENT '权限规则分类,请加应用前缀,如admin_',
  `name` varchar(100) NOT NULL DEFAULT '' COMMENT '规则唯一英文标识,全小写',
  `param` varchar(100) NOT NULL DEFAULT '' COMMENT '额外url参数',
  `title` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '规则描述',
  `condition` varchar(200) NOT NULL DEFAULT '' COMMENT '规则附加条件',
  PRIMARY KEY (`id`),
  UNIQUE KEY `name` (`name`) USING BTREE,
  KEY `module` (`app`,`status`,`type`)
) ENGINE=InnoDB AUTO_INCREMENT=157 DEFAULT CHARSET=utf8mb4 COMMENT='权限规则表';

备注
只有在这张表中的菜单才验证权限,否则视为拥有此权限。
后台添加菜单才会在此表中自动插入数据。

2.相关文件和流程

流程图

mark

2.1 用户登录判断权限

  • 文件路径 D:\www\thinkcmf\simplewind\cmf\controller\AdminBaseController.php
  • 代码内容
/**
    *  检查后台用户访问权限
    * @param int $userId 后台用户id
    * @return boolean 检查通过返回true
    */
    private function checkAccess($userId)
    {
        // 如果用户id是1,则无需判断
        if ($userId == 1) {
            return true;
        }

        $module    = $this->request->module();
        $controller = $this->request->controller();
        $action    = $this->request->action();
        $rule      = $module . $controller . $action;

        $notRequire = ["adminIndexindex", "adminMainindex"];
        if (!in_array($rule, $notRequire)) {
            return cmf_auth_check($userId);
        } else {
            return true;
        }
    }

2.2 检查权限的函数

  • 文件路径 D:\www\thinkcmf\simplewind\cmf\common.php
  • 代码内容
/**
* 检查权限
* @param $userId  int        要检查权限的用户 ID
* @param $name string|array  需要验证的规则列表,支持逗号分隔的权限规则或索引数组
* @param $relation string    如果为 'or' 表示满足任一条规则即通过验证;如果为 'and'则表示需满足所有规则才能通过验证
* @return boolean            通过验证返回true;失败返回false
*/
function cmf_auth_check($userId, $name = null, $relation = 'or')
{
    if (empty($userId)) {
        return false;
    }

    if ($userId == 1) {
        return true;
    }

    $authObj = new \cmf\lib\Auth();
    if (empty($name)) {
        $request    = request();
        $module    = $request->module();
        $controller = $request->controller();
        $action    = $request->action();
        $name      = strtolower($module . "/" . $controller . "/" . $action);
    }
    return $authObj->check($userId, $name, $relation);
}

2.3 thinkcmf授权认证类

  • 文件路径 D:\www\thinkcmf\simplewind\cmf\lib\Auth.php
  • 代码内容

namespace cmf\lib; use think\Db; /** * ThinkCMF权限认证类 */ class Auth { //默认配置 protected $_config = []; public function __construct() { } /** * 检查权限 * @param $name string|array 需要验证的规则列表,支持逗号分隔的权限规则或索引数组 * @param $uid int 认证用户的id * @param $relation string 如果为 'or' 表示满足任一条规则即通过验证;如果为 'and'则表示需满足所有规则才能通过验证 * @return boolean 通过验证返回true;失败返回false */ public function check($uid, $name, $relation = 'or') { if (empty($uid)) { return false; } if ($uid == 1) { return true; } if (is_string($name)) { $name = strtolower($name); if (strpos($name, ',') !== false) { $name = explode(',', $name); } else { $findAuthRuleCount = Db::name('auth_rule')->where([ 'name' => $name ])->count(); if ($findAuthRuleCount == 0) {//没有规则时,不验证! return true; } $name = [$name]; } } $list = []; //保存验证通过的规则名 $groups = Db::name('RoleUser') ->alias("a") ->join('__ROLE__ r', 'a.role_id = r.id') ->where(["a.user_id" => $uid, "r.status" => 1]) ->column("role_id"); if (in_array(1, $groups)) { return true; } if (empty($groups)) { return false; } $rules = Db::name('AuthAccess') ->alias("a") ->join('__AUTH_RULE__ b ', ' a.rule_name = b.name') ->where(["a.role_id" => ["in", $groups], "b.name" => ["in", $name]]) ->select(); foreach ($rules as $rule) { if (!empty($rule['condition'])) { //根据condition进行验证 $user = $this->getUserInfo($uid);//获取用户信息,一维数组 $command = preg_replace('/\{(\w*?)\}/', '$user[\'\\1\']', $rule['condition']); //dump($command);//debug @(eval('$condition=(' . $command . ');')); if ($condition) { $list[] = strtolower($rule['name']); } } else { $list[] = strtolower($rule['name']); } } if ($relation == 'or' and !empty($list)) { return true; } $diff = array_diff($name, $list); if ($relation == 'and' and empty($diff)) { return true; } return false; } /** * 获得用户资料 * @param $uid * @return mixed */ private function getUserInfo($uid) { static $userInfo = []; if (!isset($userInfo[$uid])) { $userInfo[$uid] = Db::name('user')->where(['id' => $uid])->find(); } return $userInfo[$uid]; } }

2.4 权限控制器

  • 路径 D:\www\thinkcmf\app\admin\controller\RbacController.php
  • 代码内容
<?php

namespace app\admin\controller;

use cmf\controller\AdminBaseController;
use think\Db;
use tree\Tree;
use app\admin\model\AdminMenuModel;

class RbacController extends AdminBaseController
{

    /**
    * 角色管理列表
    * @adminMenu(
    *    'name'  => '角色管理',
    *    'parent' => 'admin/User/default',
    *    'display'=> true,
    *    'hasView'=> true,
    *    'order'  => 10000,
    *    'icon'  => '',
    *    'remark' => '角色管理',
    *    'param'  => ''
    * )
    */
    public function index()
    {
        $data = Db::name('role')->order(["list_order" => "ASC", "id" => "DESC"])->select();
        $this->assign("roles", $data);
        return $this->fetch();
    }

    /**
    * 添加角色
    * @adminMenu(
    *    'name'  => '添加角色',
    *    'parent' => 'index',
    *    'display'=> false,
    *    'hasView'=> true,
    *    'order'  => 10000,
    *    'icon'  => '',
    *    'remark' => '添加角色',
    *    'param'  => ''
    * )
    */
    public function roleAdd()
    {
        return $this->fetch();
    }

    /**
    * 添加角色提交
    * @adminMenu(
    *    'name'  => '添加角色提交',
    *    'parent' => 'index',
    *    'display'=> false,
    *    'hasView'=> false,
    *    'order'  => 10000,
    *    'icon'  => '',
    *    'remark' => '添加角色提交',
    *    'param'  => ''
    * )
    */
    public function roleAddPost()
    {
        if ($this->request->isPost()) {
            $data  = $this->request->param();
            $result = $this->validate($data, 'role');
            if ($result !== true) {
                // 验证失败 输出错误信息
                $this->error($result);
            } else {
                $result = Db::name('role')->insert($data);
                if ($result) {
                    $this->success("添加角色成功", url("rbac/index"));
                } else {
                    $this->error("添加角色失败");
                }

            }
        }
    }

    /**
    * 编辑角色
    * @adminMenu(
    *    'name'  => '编辑角色',
    *    'parent' => 'index',
    *    'display'=> false,
    *    'hasView'=> true,
    *    'order'  => 10000,
    *    'icon'  => '',
    *    'remark' => '编辑角色',
    *    'param'  => ''
    * )
    */
    public function roleEdit()
    {
        $id = $this->request->param("id", 0, 'intval');
        if ($id == 1) {
            $this->error("超级管理员角色不能被修改!");
        }
        $data = Db::name('role')->where(["id" => $id])->find();
        if (!$data) {
            $this->error("该角色不存在!");
        }
        $this->assign("data", $data);
        return $this->fetch();
    }

    /**
    * 编辑角色提交
    * @adminMenu(
    *    'name'  => '编辑角色提交',
    *    'parent' => 'index',
    *    'display'=> false,
    *    'hasView'=> false,
    *    'order'  => 10000,
    *    'icon'  => '',
    *    'remark' => '编辑角色提交',
    *    'param'  => ''
    * )
    */
    public function roleEditPost()
    {
        $id = $this->request->param("id", 0, 'intval');
        if ($id == 1) {
            $this->error("超级管理员角色不能被修改!");
        }
        if ($this->request->isPost()) {
            $data  = $this->request->param();
            $result = $this->validate($data, 'role');
            if ($result !== true) {
                // 验证失败 输出错误信息
                $this->error($result);

            } else {
                if (Db::name('role')->update($data) !== false) {
                    $this->success("保存成功!", url('rbac/index'));
                } else {
                    $this->error("保存失败!");
                }
            }
        }
    }

    /**
    * 删除角色
    * @adminMenu(
    *    'name'  => '删除角色',
    *    'parent' => 'index',
    *    'display'=> false,
    *    'hasView'=> false,
    *    'order'  => 10000,
    *    'icon'  => '',
    *    'remark' => '删除角色',
    *    'param'  => ''
    * )
    */
    public function roleDelete()
    {
        $id = $this->request->param("id", 0, 'intval');
        if ($id == 1) {
            $this->error("超级管理员角色不能被删除!");
        }
        $count = Db::name('RoleUser')->where(['role_id' => $id])->count();
        if ($count > 0) {
            $this->error("该角色已经有用户!");
        } else {
            $status = Db::name('role')->delete($id);
            if (!empty($status)) {
                $this->success("删除成功!", url('rbac/index'));
            } else {
                $this->error("删除失败!");
            }
        }
    }

    /**
    * 设置角色权限
    * @adminMenu(
    *    'name'  => '设置角色权限',
    *    'parent' => 'index',
    *    'display'=> false,
    *    'hasView'=> true,
    *    'order'  => 10000,
    *    'icon'  => '',
    *    'remark' => '设置角色权限',
    *    'param'  => ''
    * )
    */
    public function authorize()
    {
        $AuthAccess    = Db::name("AuthAccess");
        $adminMenuModel = new AdminMenuModel();
        //角色ID
        $roleId = $this->request->param("id", 0, 'intval');
        if (empty($roleId)) {
            $this->error("参数错误!");
        }

        $tree      = new Tree();
        $tree->icon = ['│ ', '├─ ', '└─ '];
        $tree->nbsp = '&nbsp;&nbsp;&nbsp;';

        $result = $adminMenuModel->menuCache();

        $newMenus      = [];
        $privilegeData = $AuthAccess->where(["role_id" => $roleId])->column("rule_name");//获取权限表数据

        foreach ($result as $m) {
            $newMenus[$m['id']] = $m;
        }

        foreach ($result as $n => $t) {
            $result[$n]['checked']      = ($this->_isChecked($t, $privilegeData)) ? ' checked' : '';
            $result[$n]['level']        = $this->_getLevel($t['id'], $newMenus);
            $result[$n]['style']        = empty($t['parent_id']) ? '' : 'display:none;';
            $result[$n]['parentIdNode'] = ($t['parent_id']) ? ' class="child-of-node-' . $t['parent_id'] . '"' : '';
        }

        $str = "<tr id='node-\$id'\$parentIdNode  style='\$style'>
                  <td style='padding-left:30px;'>\$spacer<input type='checkbox' name='menuId[]' value='\$id' level='\$level' \$checked onclick='javascript:checknode(this);'> \$name</td>
                </tr>";
        $tree->init($result);

        $category = $tree->getTree(0, $str);

        $this->assign("category", $category);
        $this->assign("roleId", $roleId);
        return $this->fetch();
    }

    /**
    * 角色授权提交
    * @adminMenu(
    *    'name'  => '角色授权提交',
    *    'parent' => 'index',
    *    'display'=> false,
    *    'hasView'=> false,
    *    'order'  => 10000,
    *    'icon'  => '',
    *    'remark' => '角色授权提交',
    *    'param'  => ''
    * )
    */
    public function authorizePost()
    {
        if ($this->request->isPost()) {
            $roleId = $this->request->param("roleId", 0, 'intval');
            if (!$roleId) {
                $this->error("需要授权的角色不存在!");
            }
            if (is_array($this->request->param('menuId/a')) && count($this->request->param('menuId/a')) > 0) {

                Db::name("authAccess")->where(["role_id" => $roleId, 'type' => 'admin_url'])->delete();
                foreach ($_POST['menuId'] as $menuId) {
                    $menu = Db::name("adminMenu")->where(["id" => $menuId])->field("app,controller,action")->find();
                    if ($menu) {
                        $app    = $menu['app'];
                        $model  = $menu['controller'];
                        $action = $menu['action'];
                        $name  = strtolower("$app/$model/$action");
                        Db::name("authAccess")->insert(["role_id" => $roleId, "rule_name" => $name, 'type' => 'admin_url']);
                    }
                }

                $this->success("授权成功!");
            } else {
                //当没有数据时,清除当前角色授权
                Db::name("authAccess")->where(["role_id" => $roleId])->delete();
                $this->error("没有接收到数据,执行清除授权成功!");
            }
        }
    }

    /**
    * 检查指定菜单是否有权限
    * @param array $menu menu表中数组
    * @param $privData
    * @return bool
    */
    private function _isChecked($menu, $privData)
    {
        $app    = $menu['app'];
        $model  = $menu['controller'];
        $action = $menu['action'];
        $name  = strtolower("$app/$model/$action");
        if ($privData) {
            if (in_array($name, $privData)) {
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }

    }

    /**
    * 获取菜单深度
    * @param $id
    * @param array $array
    * @param int $i
    * @return int
    */
    protected function _getLevel($id, $array = [], $i = 0)
    {
        if ($array[$id]['parent_id'] == 0 || empty($array[$array[$id]['parent_id']]) || $array[$id]['parent_id'] == $id) {
            return $i;
        } else {
            $i++;
            return $this->_getLevel($array[$id]['parent_id'], $array, $i);
        }
    }

    //角色成员管理
    public function member()
    {
        //TODO 添加角色成员管理

    }

}


未经允许不得转载:NewThink » thinkcmf权限管理系统

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址