正文
这是在一个项目中,接触到的比较好的一个权限控制系统,重要的是里面的思想,框架借用了ThinkPHP3.2,其实不用TP也可以,你可以很方便的二次开发。
先说数据库权限相关表的结构:
CREATE TABLE `admin` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '管理员主键',
`admin_name` varchar(20) NOT NULL COMMENT '用户名',
`password` varchar(32) NOT NULL COMMENT '密码',
`last_time` int(11) DEFAULT NULL COMMENT '最近登录时间',
`last_ip` varchar(20) DEFAULT NULL COMMENT '最近登录IP',
PRIMARY KEY (`id`),
UNIQUE KEY `admin_name` (`admin_name`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='管理员用户表';
CREATE TABLE `group` (
`id` int(4) NOT NULL AUTO_INCREMENT COMMENT '主键,标识',
`group_name` varchar(14) NOT NULL COMMENT '管理组名称',
`group_infor` varchar(200) NOT NULL COMMENT '管理组说明',
`rank` int(2) NOT NULL COMMENT '排序',
PRIMARY KEY (`id`),
UNIQUE KEY `group_name` (`group_name`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='管理员组表';
CREATE TABLE `admin_group` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`admin_id` int(11) NOT NULL COMMENT '管理员ID, admin表的主键',
`group_id` int(11) NOT NULL COMMENT '管理组id, group表的主键',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='管理员所属管理组表';
CREATE TABLE `webmenu` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`menu_name` varchar(20) NOT NULL COMMENT '菜单名',
`menu_rank` int(11) NOT NULL COMMENT '排序',
`menu_controllers` varchar(200) NOT NULL COMMENT '菜单所属控制器',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='菜单表';
CREATE TABLE `power` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`pid` int(3) NOT NULL COMMENT '菜单id, webmenu表的主键',
`title` varchar(20) NOT NULL COMMENT '权限名称',
`type` int(2) NOT NULL COMMENT '操作类型: 1 操作控制 ; 2 菜单类别; 3 其他类别',
`rank` int(2) NOT NULL COMMENT '排序',
`power_id` varchar(40) NOT NULL DEFAULT '' COMMENT 'module-controller-action',
PRIMARY KEY (`id`),
UNIQUE KEY `power_id` (`power_id`) USING BTREE,
KEY `id` (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='权限表';
CREATE TABLE `admin_power` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`admin_id` int(11) NOT NULL COMMENT '用户id',
`power_id` int(11) NOT NULL COMMENT '权限表id',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='用户权限表';
CREATE TABLE `group_power` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`group_id` int(11) NOT NULL COMMENT '用户组id',
`power_id` int(11) NOT NULL COMMENT '权限表id',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='用户组权限表';
权限控制器CheckPower的代码:
namespace Home\Controller;
use Think\Controller;
class CheckPowerController extends Controller
{
public function _initialize ()
{
// 判断是否登录
$admin_id = $_SESSION['admin_id']; // TP下可以写成session('admin_id');
if ( empty($admin_id) ) {
$this->error('登录超时', U('Index/login'));
}
// 操作方法的权限判断
$auth= new \ClassLib\Power();
if ( !$auth->check( $admin_id, MODULE_NAME.'-'.CONTROLLER_NAME.'-'.ACTION_NAME ) ) {
$this->error('你没有权限');
}
}
}
这里把模块-控制器-方法拼装好,和用户id一起传到权限检查类的check方法中检查。
看一下文件位置:
文件内容:
<?php
namespace ClassLib;
class Power
{
// 权限检查
public function check ( $admin_id, $m_c_a_url )
{
$power_arr = $this->getAllPowers( $admin_id );
$power = M('power');
$map['power_id'] = strtolower($m_c_a_url);
$power_id = $power->field('id')->where( $map )->find();
return in_array($power_id['id'], $power_arr);
}
// 获取用户(及所在用户组)权限
public function getAllPowers ( $admin_id )
{
// 用户个人权限
$power_admin = $this->getPowers( $admin_id, 'admin');
// 获取所属用户组的id
$groups_id_arr = $this->getGroups( $admin_id );
// 所属用户组的权限
$power_group = $this->getPowers( $groups_id_arr, 'group');
$power_admin = !empty($power_admin ) ? $power_admin : array();
$power_group = !empty($power_group ) ? $power_group : array();
//合并用户权限 和 用户组权限
$power_arr = array_unique( array_merge( $power_admin, $power_group ) );
return $power_arr;
}
public function getGroups ( $admin_id )
{
$group_ID_arr = NULL;
$map['admin_id'] = $admin_id;
$data = M("admin_group")->where( $map )->select();
if ( !is_null($data) ) {
foreach ($data as $key => $value)
{
$group_ID_arr[] = $value['group_id'];
}
}
return $group_ID_arr;
}
public function getPowers ( $ids, $type )
{
$power_arr = null;
$data = null;
if ( $type == 'admin' ) {
$condition['admin_id'] = $ids;
$data = M("admin_power")->where( $condition )->select();
} elseif ($type == 'group') {
$condition['group_id'] = array('in', $ids);
$data = M("group_power")->where( $condition )->select();
}
if ( !is_null($data) ) {
foreach ($data as $key => $value)
{
$power_arr[] = $value['power_id'];
}
}
return $power_arr;
}
// 生成菜单
public function getMenu ( $admin_id )
{
$power_arr = $this->getAllPowers( $admin_id );
if ( empty($power_arr) ) {
exit('好像管理员忘记给你分配权限了。');
}
$power = M('power');
$where['id'] = array('in', $power_arr);
// 读取到权限的所有属性
$power_list = $power->where($where)->order('rank')->select();
// 所有的菜单大类
$webmenu = M('webmenu');
$webmenu_list = $webmenu->order('menu_rank')->select();
$len_webmenu_list = count($webmenu_list);
// 循环把权限属性,整理到菜单数组中去
for ( $i = 0; $i < $len_webmenu_list; $i++ )
{
for ( $j = 0; $j < count($power_list); $j++ )
{
// 判断这个菜单下有无菜单类型权限
if ( $power_list[$j]['pid'] == $webmenu_list[$i]['id'] ) {
$webmenu_list[$i]['power'][$power_list[$j]['id']] = $power_list[$j];
}
}
}
// 菜单html拼接
$menu_html = '';
for ( $i = 0; $i < $len_webmenu_list; $i++ )
{
$ispower = false; // 当前菜单是否有子菜单
$menu_li = null; // 当前菜单的子菜单拼装
foreach ( $webmenu_list[$i]['power'] as $key => $value )
{
if ( $value['type'] == 2 ) {
$action = explode('-', $value['power_id']);
$len_action = count($action);
if ( $len_action == 3 ) {
if ( $action[0] != 'home' ) {
$url = $action[0] . '/' . $action[1] . '/' . $action[2];
} else {
$url = $action[1] . '/' . $action[2];
}
} else {
$url = '#';
}
$menu_li .= '<li><a href="' .U($url) .'">' .$value['title'] .'</a></li>';
$ispower = true;
}
}
if ( $ispower ) {
$menu_html .= '<h3 item="' .$webmenu_list[$i]['menu_controllers'] .'"><em></em>' .$webmenu_lists[$i]['menu_name'] .'</h3><ul>' .$menu_li .'</ul>';
}
}
return $menu_html;
}
}