2018-11-28 03:07:06 +00:00
< ? 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 ;
}
2018-08-04 17:54:43 +00:00
}