1.數(shù)據(jù)庫結(jié)構(gòu)
用戶表
CREATE TABLE `think_user` (
`id` int(11) NOT NULL AUTO_INCREMENT, //主鍵id
`username` varchar(30) DEFAULT NULL, //用戶名
`password` varchar(32) DEFAULT NULL, //密碼
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
權(quán)限節(jié)點表
CREATE TABLE `think_auth_rule` (
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT, //主鍵id
`name` char(80) NOT NULL DEFAULT '' COMMENT '規(guī)則唯一標(biāo)識', //描述
`url` char(20) NOT NULL DEFAULT '' COMMENT '規(guī)則中文名稱', //路徑如:Index/index
`status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '狀態(tài):為1正常,為0禁用',
`pcontroller` char(80) NOT NULL, //上次控制器
`condition` char(100) NOT NULL DEFAULT '' COMMENT '規(guī)則表達(dá)式扫倡,為空表示存在就驗證谦秧,不為空表示按照條件驗',
`type` tinyint(1) NOT NULL DEFAULT '1',
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
) ENGINE=MyISAM AUTO_INCREMENT=11 DEFAULT CHARSET=utf8 COMMENT='規(guī)則表';
用戶組--用戶關(guān)聯(lián)表
CREATE TABLE `think_auth_group_access` (
`uid` mediumint(8) unsigned NOT NULL COMMENT '用戶id',
`group_id` mediumint(8) unsigned NOT NULL COMMENT '用戶組id',
UNIQUE KEY `uid_group_id` (`uid`,`group_id`),
KEY `uid` (`uid`),
KEY `group_id` (`group_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='用戶組明細(xì)表';
用戶組表
CREATE TABLE `think_auth_group` (
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT, //主鍵id
`name` char(100) NOT NULL DEFAULT '',//用戶組名稱
`status` tinyint(1) NOT NULL DEFAULT '1',//用戶組狀態(tài)
`rules` char(80) NOT NULL DEFAULT '',//用戶組關(guān)聯(lián)的權(quán)限節(jié)點id(多個)
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=9 DEFAULT CHARSET=utf8 COMMENT='用戶組表';
2.認(rèn)證類
classAuth{
//默認(rèn)配置
protected$_config= array(
'AUTH_ON'=> true,//認(rèn)證開關(guān)
'AUTH_TYPE'=>1,//認(rèn)證方式,1為實時認(rèn)證撵溃;2為登錄認(rèn)證疚鲤。
'AUTH_GROUP'=>'think_auth_group',//用戶組數(shù)據(jù)表名
'AUTH_GROUP_ACCESS'=>'think_auth_group_access',//用戶-用戶組關(guān)系表
'AUTH_RULE'=>'think_auth_rule',//權(quán)限規(guī)則表
'AUTH_USER'=>'think_user'//用戶信息表
);
public function__construct() {
header("Content-type: text/html; charset=utf-8");
if(Config::get('auth_config')) {
$this->_config=array_merge($this->_config,Config::get('auth_config'));//可設(shè)置配置項auth_config,此配置項為數(shù)組。
}
}
/**
*檢查權(quán)限
* @param name string|array需要驗證的規(guī)則列表,支持逗號分隔的權(quán)限規(guī)則或索引數(shù)組
* @param uid? int認(rèn)證用戶的id
* @param string mode執(zhí)行check的模式
* @param relation string如果為'or'表示滿足任一條規(guī)則即通過驗證;如果為'and'則表示需滿足所有規(guī)則才能通過驗證
* @return boolean通過驗證返回true;失敗返回false
*/
public functioncheck($name,$uid,$type=1,$mode='url',$relation='or') {
if(!$this->_config['AUTH_ON'])
return true;
$authList=$this->getAuthList($uid,$type);//獲取用戶需要驗證的所有有效規(guī)則列表
if(is_string($name)) {
$name=strtolower($name);
$name=strpos($name,',')!== false ?explode(',',$name): array($name);
}
$list= array();//保存驗證通過的規(guī)則名
if($mode=='url') {
$REQUEST=unserialize(strtolower(serialize($_REQUEST)) );
}
foreach($authListas$auth) {
$query=preg_replace('/^.+\?/U','',$auth);
if($mode=='url'&&$query!=$auth) {
parse_str($query,$param);//解析規(guī)則中的param
$intersect=array_intersect_assoc($REQUEST,$param);
$auth=preg_replace('/\?.*$/U','',$auth);
if(in_array($auth,$name)&&$intersect==$param) {//如果節(jié)點相符且url參數(shù)滿足
$list[]=$auth;
}
}else if(in_array($auth,$name)){
$list[]=$auth;
}
}
if($relation=='or'and !empty($list)) {
return true;
}
$diff=array_diff($name,$list);
if($relation=='and'and empty($diff)) {
return true;
}
return false;
}
/**
*根據(jù)用戶id獲取用戶組,返回值為數(shù)組
* @param? uid int用戶id
* @return array用戶所屬的用戶組array(
*? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? array('uid'=>'用戶id','group_id'=>'用戶組id','title'=>'用戶組名稱','rules'=>'用戶組擁有的規(guī)則id,多個,號隔開'),
*? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ...)
*/
public functiongetGroups($uid) {
static$groups= array();
if(isset($groups[$uid]))
return$groups[$uid];
$user_groups=Db::view($this->_config['AUTH_GROUP_ACCESS'],'uid,group_id')->view($this->_config['AUTH_GROUP'],'name,rules',"{$this->_config['AUTH_GROUP_ACCESS']}.group_id={$this->_config['AUTH_GROUP']}.id")
->where(['uid'=>$uid,'status'=>1])->select();
$groups[$uid]=$user_groups?:array();
return$groups[$uid];
}
/**
*獲得權(quán)限列表
* @param integer $uid用戶id
* @param integer $type
*/
protected functiongetAuthList($uid,$type) {
static$_authList= array();//保存用戶驗證通過的權(quán)限列表
$t=implode(',',(array)$type);
if(isset($_authList[$uid.$t])) {
return$_authList[$uid.$t];
}
if($this->_config['AUTH_TYPE']==2&& isset($_SESSION['_AUTH_LIST_'.$uid.$t])){
return$_SESSION['_AUTH_LIST_'.$uid.$t];
}
//讀取用戶所屬用戶組
$groups=$this->getGroups($uid);
$ids= array();//保存用戶所屬用戶組設(shè)置的所有權(quán)限規(guī)則id
foreach($groupsas$g) {
$ids=array_merge($ids,explode(',',trim($g['rules'],',')));
}
$ids=array_unique($ids);
if(empty($ids)) {
$_authList[$uid.$t]= array();
return array();
}
$map=array(
'id'=>array('in',$ids),
'type'=>$type,
'status'=>0,
);
//讀取用戶組所有權(quán)限規(guī)則
$rules=Db::table($this->_config['AUTH_RULE'])->where($map)->field('condition,name,url')->select();
//循環(huán)規(guī)則缘挑,判斷結(jié)果集歇。
$authList= array();//
foreach($rulesas$rule) {
if(!empty($rule['condition'])) {//根據(jù)condition進(jìn)行驗證
$user=$this->getUserInfo($uid);//獲取用戶信息,一維數(shù)組
$command=preg_replace('/\{(\w*?)\}/','$user[\'\\1\']',$rule['condition']);
//dump($command);//debug
@(eval('$condition=('.$command.');'));
if($condition) {
$authList[]=strtolower($rule['url']);
}
}else{
//只要存在就記錄
$authList[]=strtolower($rule['url']);
}
}
$_authList[$uid.$t]=$authList;
if($this->_config['AUTH_TYPE']==2){
//規(guī)則列表結(jié)果保存到session
$_SESSION['_AUTH_LIST_'.$uid.$t]=$authList;
}
returnarray_unique($authList);
}
/**
*獲得用戶資料,根據(jù)自己的情況讀取數(shù)據(jù)庫
*/
protected functiongetUserInfo($uid) {
static$userinfo=array();
if(!isset($userinfo[$uid])){
$userinfo[$uid]=Db::table($this->_config['AUTH_USER'])->where(['id'=>$uid])->find();
}
return$userinfo[$uid];
}
}
3.登錄時使用
public function login(){
$uid=1;? //登錄后的用戶id
vendor("Auth"); //因為是將認(rèn)證類作為自己的第三方包寫的,所以使用時需要先導(dǎo)入
$auth= newAuth();
$name=Request::instance()->controller().'/'.Request::instance()->action(); //如需要驗證Index/index 登錄的用戶是否有操作該類的權(quán)限
$res=$auth->check($name,$uid);? //調(diào)用驗證方法里的驗證
if(!$res){
echo'你沒有權(quán)限';
}else{
echo'登錄成功';
}
}