You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
285 lines
12 KiB
PHTML
285 lines
12 KiB
PHTML
5 years ago
|
<?php
|
||
|
// +----------------------------------------------------------------------
|
||
|
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
|
||
|
// +----------------------------------------------------------------------
|
||
|
// | Copyright (c) 2009 http://thinkphp.cn All rights reserved.
|
||
|
// +----------------------------------------------------------------------
|
||
|
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||
|
// +----------------------------------------------------------------------
|
||
|
// | Author: liu21st <liu21st@gmail.com>
|
||
|
// +----------------------------------------------------------------------
|
||
|
namespace Org\Util;
|
||
|
use Think\Db;
|
||
|
/**
|
||
|
+------------------------------------------------------------------------------
|
||
|
* 基于角色的数据库方式验证类
|
||
|
+------------------------------------------------------------------------------
|
||
|
*/
|
||
|
// 配置文件增加设置
|
||
|
// USER_AUTH_ON 是否需要认证
|
||
|
// USER_AUTH_TYPE 认证类型
|
||
|
// USER_AUTH_KEY 认证识别号
|
||
|
// REQUIRE_AUTH_MODULE 需要认证模块
|
||
|
// NOT_AUTH_MODULE 无需认证模块
|
||
|
// USER_AUTH_GATEWAY 认证网关
|
||
|
// RBAC_DB_DSN 数据库连接DSN
|
||
|
// RBAC_ROLE_TABLE 角色表名称
|
||
|
// RBAC_USER_TABLE 用户表名称
|
||
|
// RBAC_ACCESS_TABLE 权限表名称
|
||
|
// RBAC_NODE_TABLE 节点表名称
|
||
|
/*
|
||
|
-- --------------------------------------------------------
|
||
|
CREATE TABLE IF NOT EXISTS `think_access` (
|
||
|
`role_id` smallint(6) unsigned NOT NULL,
|
||
|
`node_id` smallint(6) unsigned NOT NULL,
|
||
|
`level` tinyint(1) NOT NULL,
|
||
|
`module` varchar(50) DEFAULT NULL,
|
||
|
KEY `groupId` (`role_id`),
|
||
|
KEY `nodeId` (`node_id`)
|
||
|
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||
|
|
||
|
CREATE TABLE IF NOT EXISTS `think_node` (
|
||
|
`id` smallint(6) unsigned NOT NULL AUTO_INCREMENT,
|
||
|
`name` varchar(20) NOT NULL,
|
||
|
`title` varchar(50) DEFAULT NULL,
|
||
|
`status` tinyint(1) DEFAULT '0',
|
||
|
`remark` varchar(255) DEFAULT NULL,
|
||
|
`sort` smallint(6) unsigned DEFAULT NULL,
|
||
|
`pid` smallint(6) unsigned NOT NULL,
|
||
|
`level` tinyint(1) unsigned NOT NULL,
|
||
|
PRIMARY KEY (`id`),
|
||
|
KEY `level` (`level`),
|
||
|
KEY `pid` (`pid`),
|
||
|
KEY `status` (`status`),
|
||
|
KEY `name` (`name`)
|
||
|
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||
|
|
||
|
CREATE TABLE IF NOT EXISTS `think_role` (
|
||
|
`id` smallint(6) unsigned NOT NULL AUTO_INCREMENT,
|
||
|
`name` varchar(20) NOT NULL,
|
||
|
`pid` smallint(6) DEFAULT NULL,
|
||
|
`status` tinyint(1) unsigned DEFAULT NULL,
|
||
|
`remark` varchar(255) DEFAULT NULL,
|
||
|
PRIMARY KEY (`id`),
|
||
|
KEY `pid` (`pid`),
|
||
|
KEY `status` (`status`)
|
||
|
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ;
|
||
|
|
||
|
CREATE TABLE IF NOT EXISTS `think_role_user` (
|
||
|
`role_id` mediumint(9) unsigned DEFAULT NULL,
|
||
|
`user_id` char(32) DEFAULT NULL,
|
||
|
KEY `group_id` (`role_id`),
|
||
|
KEY `user_id` (`user_id`)
|
||
|
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||
|
*/
|
||
|
class Rbac {
|
||
|
// 认证方法
|
||
|
static public function authenticate($map,$model='') {
|
||
|
if(empty($model)) $model = C('USER_AUTH_MODEL');
|
||
|
//使用给定的Map进行认证
|
||
|
return M($model)->where($map)->find();
|
||
|
}
|
||
|
|
||
|
//用于检测用户权限的方法,并保存到Session中
|
||
|
static function saveAccessList($authId=null) {
|
||
|
if(null===$authId) $authId = $_SESSION[C('USER_AUTH_KEY')];
|
||
|
// 如果使用普通权限模式,保存当前用户的访问权限列表
|
||
|
// 对管理员开发所有权限
|
||
|
if(C('USER_AUTH_TYPE') !=2 && !$_SESSION[C('ADMIN_AUTH_KEY')] )
|
||
|
$_SESSION['_ACCESS_LIST'] = self::getAccessList($authId);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
// 取得模块的所属记录访问权限列表 返回有权限的记录ID数组
|
||
|
static function getRecordAccessList($authId=null,$module='') {
|
||
|
if(null===$authId) $authId = $_SESSION[C('USER_AUTH_KEY')];
|
||
|
if(empty($module)) $module = CONTROLLER_NAME;
|
||
|
//获取权限访问列表
|
||
|
$accessList = self::getModuleAccessList($authId,$module);
|
||
|
return $accessList;
|
||
|
}
|
||
|
|
||
|
//检查当前操作是否需要认证
|
||
|
static function checkAccess() {
|
||
|
//如果项目要求认证,并且当前模块需要认证,则进行权限认证
|
||
|
if( C('USER_AUTH_ON') ){
|
||
|
$_module = array();
|
||
|
$_action = array();
|
||
|
if("" != C('REQUIRE_AUTH_MODULE')) {
|
||
|
//需要认证的模块
|
||
|
$_module['yes'] = explode(',',strtoupper(C('REQUIRE_AUTH_MODULE')));
|
||
|
}else {
|
||
|
//无需认证的模块
|
||
|
$_module['no'] = explode(',',strtoupper(C('NOT_AUTH_MODULE')));
|
||
|
}
|
||
|
//检查当前模块是否需要认证
|
||
|
if((!empty($_module['no']) && !in_array(strtoupper(CONTROLLER_NAME),$_module['no'])) || (!empty($_module['yes']) && in_array(strtoupper(CONTROLLER_NAME),$_module['yes']))) {
|
||
|
if("" != C('REQUIRE_AUTH_ACTION')) {
|
||
|
//需要认证的操作
|
||
|
$_action['yes'] = explode(',',strtoupper(C('REQUIRE_AUTH_ACTION')));
|
||
|
}else {
|
||
|
//无需认证的操作
|
||
|
$_action['no'] = explode(',',strtoupper(C('NOT_AUTH_ACTION')));
|
||
|
}
|
||
|
//检查当前操作是否需要认证
|
||
|
if((!empty($_action['no']) && !in_array(strtoupper(ACTION_NAME),$_action['no'])) || (!empty($_action['yes']) && in_array(strtoupper(ACTION_NAME),$_action['yes']))) {
|
||
|
return true;
|
||
|
}else {
|
||
|
return false;
|
||
|
}
|
||
|
}else {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// 登录检查
|
||
|
static public function checkLogin() {
|
||
|
//检查当前操作是否需要认证
|
||
|
if(self::checkAccess()) {
|
||
|
//检查认证识别号
|
||
|
if(!$_SESSION[C('USER_AUTH_KEY')]) {
|
||
|
if(C('GUEST_AUTH_ON')) {
|
||
|
// 开启游客授权访问
|
||
|
if(!isset($_SESSION['_ACCESS_LIST']))
|
||
|
// 保存游客权限
|
||
|
self::saveAccessList(C('GUEST_AUTH_ID'));
|
||
|
}else{
|
||
|
// 禁止游客访问跳转到认证网关
|
||
|
redirect(PHP_FILE.C('USER_AUTH_GATEWAY'));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
//权限认证的过滤器方法
|
||
|
static public function AccessDecision($appName=MODULE_NAME) {
|
||
|
//检查是否需要认证
|
||
|
if(self::checkAccess()) {
|
||
|
//存在认证识别号,则进行进一步的访问决策
|
||
|
$accessGuid = md5($appName.CONTROLLER_NAME.ACTION_NAME);
|
||
|
if(empty($_SESSION[C('ADMIN_AUTH_KEY')])) {
|
||
|
if(C('USER_AUTH_TYPE')==2) {
|
||
|
//加强验证和即时验证模式 更加安全 后台权限修改可以即时生效
|
||
|
//通过数据库进行访问检查
|
||
|
$accessList = self::getAccessList($_SESSION[C('USER_AUTH_KEY')]);
|
||
|
}else {
|
||
|
// 如果是管理员或者当前操作已经认证过,无需再次认证
|
||
|
if( $_SESSION[$accessGuid]) {
|
||
|
return true;
|
||
|
}
|
||
|
//登录验证模式,比较登录后保存的权限访问列表
|
||
|
$accessList = $_SESSION['_ACCESS_LIST'];
|
||
|
}
|
||
|
//判断是否为组件化模式,如果是,验证其全模块名
|
||
|
if(!isset($accessList[strtoupper($appName)][strtoupper(CONTROLLER_NAME)][strtoupper(ACTION_NAME)])) {
|
||
|
$_SESSION[$accessGuid] = false;
|
||
|
return false;
|
||
|
}
|
||
|
else {
|
||
|
$_SESSION[$accessGuid] = true;
|
||
|
}
|
||
|
}else{
|
||
|
//管理员无需认证
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
+----------------------------------------------------------
|
||
|
* 取得当前认证号的所有权限列表
|
||
|
+----------------------------------------------------------
|
||
|
* @param integer $authId 用户ID
|
||
|
+----------------------------------------------------------
|
||
|
* @access public
|
||
|
+----------------------------------------------------------
|
||
|
*/
|
||
|
static public function getAccessList($authId) {
|
||
|
// Db方式权限数据
|
||
|
$db = Db::getInstance(C('RBAC_DB_DSN'));
|
||
|
$table = array('role'=>C('RBAC_ROLE_TABLE'),'user'=>C('RBAC_USER_TABLE'),'access'=>C('RBAC_ACCESS_TABLE'),'node'=>C('RBAC_NODE_TABLE'));
|
||
|
$sql = "select node.id,node.name from ".
|
||
|
$table['role']." as role,".
|
||
|
$table['user']." as user,".
|
||
|
$table['access']." as access ,".
|
||
|
$table['node']." as node ".
|
||
|
"where user.user_id='{$authId}' and user.role_id=role.id and ( access.role_id=role.id or (access.role_id=role.pid and role.pid!=0 ) ) and role.status=1 and access.node_id=node.id and node.level=1 and node.status=1";
|
||
|
$apps = $db->query($sql);
|
||
|
$access = array();
|
||
|
foreach($apps as $key=>$app) {
|
||
|
$appId = $app['id'];
|
||
|
$appName = $app['name'];
|
||
|
// 读取项目的模块权限
|
||
|
$access[strtoupper($appName)] = array();
|
||
|
$sql = "select node.id,node.name from ".
|
||
|
$table['role']." as role,".
|
||
|
$table['user']." as user,".
|
||
|
$table['access']." as access ,".
|
||
|
$table['node']." as node ".
|
||
|
"where user.user_id='{$authId}' and user.role_id=role.id and ( access.role_id=role.id or (access.role_id=role.pid and role.pid!=0 ) ) and role.status=1 and access.node_id=node.id and node.level=2 and node.pid={$appId} and node.status=1";
|
||
|
$modules = $db->query($sql);
|
||
|
// 判断是否存在公共模块的权限
|
||
|
$publicAction = array();
|
||
|
foreach($modules as $key=>$module) {
|
||
|
$moduleId = $module['id'];
|
||
|
$moduleName = $module['name'];
|
||
|
if('PUBLIC'== strtoupper($moduleName)) {
|
||
|
$sql = "select node.id,node.name from ".
|
||
|
$table['role']." as role,".
|
||
|
$table['user']." as user,".
|
||
|
$table['access']." as access ,".
|
||
|
$table['node']." as node ".
|
||
|
"where user.user_id='{$authId}' and user.role_id=role.id and ( access.role_id=role.id or (access.role_id=role.pid and role.pid!=0 ) ) and role.status=1 and access.node_id=node.id and node.level=3 and node.pid={$moduleId} and node.status=1";
|
||
|
$rs = $db->query($sql);
|
||
|
foreach ($rs as $a){
|
||
|
$publicAction[$a['name']] = $a['id'];
|
||
|
}
|
||
|
unset($modules[$key]);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
// 依次读取模块的操作权限
|
||
|
foreach($modules as $key=>$module) {
|
||
|
$moduleId = $module['id'];
|
||
|
$moduleName = $module['name'];
|
||
|
$sql = "select node.id,node.name from ".
|
||
|
$table['role']." as role,".
|
||
|
$table['user']." as user,".
|
||
|
$table['access']." as access ,".
|
||
|
$table['node']." as node ".
|
||
|
"where user.user_id='{$authId}' and user.role_id=role.id and ( access.role_id=role.id or (access.role_id=role.pid and role.pid!=0 ) ) and role.status=1 and access.node_id=node.id and node.level=3 and node.pid={$moduleId} and node.status=1";
|
||
|
$rs = $db->query($sql);
|
||
|
$action = array();
|
||
|
foreach ($rs as $a){
|
||
|
$action[$a['name']] = $a['id'];
|
||
|
}
|
||
|
// 和公共模块的操作权限合并
|
||
|
$action += $publicAction;
|
||
|
$access[strtoupper($appName)][strtoupper($moduleName)] = array_change_key_case($action,CASE_UPPER);
|
||
|
}
|
||
|
}
|
||
|
return $access;
|
||
|
}
|
||
|
|
||
|
// 读取模块所属的记录访问权限
|
||
|
static public function getModuleAccessList($authId,$module) {
|
||
|
// Db方式
|
||
|
$db = Db::getInstance(C('RBAC_DB_DSN'));
|
||
|
$table = array('role'=>C('RBAC_ROLE_TABLE'),'user'=>C('RBAC_USER_TABLE'),'access'=>C('RBAC_ACCESS_TABLE'));
|
||
|
$sql = "select access.node_id from ".
|
||
|
$table['role']." as role,".
|
||
|
$table['user']." as user,".
|
||
|
$table['access']." as access ".
|
||
|
"where user.user_id='{$authId}' and user.role_id=role.id and ( access.role_id=role.id or (access.role_id=role.pid and role.pid!=0 ) ) and role.status=1 and access.module='{$module}' and access.status=1";
|
||
|
$rs = $db->query($sql);
|
||
|
$access = array();
|
||
|
foreach ($rs as $node){
|
||
|
$access[] = $node['node_id'];
|
||
|
}
|
||
|
return $access;
|
||
|
}
|
||
|
}
|