1.数据库结构
用户表
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;
权限节点表
CREATE TABLE `think_auth_rule` (
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT, //主键id
`name` char(80) NOT NULL DEFAULT '' COMMENT '规则唯一标识', //描述
`url` char(20) NOT NULL DEFAULT '' COMMENT '规则中文名称', //路径如:Index/index
`status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '状态:为1正常,为0禁用',
`pcontroller` char(80) NOT NULL, //上次控制器
`condition` char(100) NOT NULL DEFAULT '' COMMENT '规则表达式,为空表示存在就验证,不为空表示按照条件验',
`type` tinyint(1) NOT NULL DEFAULT '1',
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
) ENGINE=MyISAM AUTO_INCREMENT=11 DEFAULT CHARSET=utf8 COMMENT='规则表';
用户组--用户关联表
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='用户组明细表';
用户组表
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',//用户组状态
`rules` char(80) NOT NULL DEFAULT '',//用户组关联的权限节点id(多个)
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=9 DEFAULT CHARSET=utf8 COMMENT='用户组表';
2.认证类
classAuth{
//默认配置
protected$_config= array(
'AUTH_ON'=> true,//认证开关
'AUTH_TYPE'=>1,//认证方式,1为实时认证;2为登录认证。
'AUTH_GROUP'=>'think_auth_group',//用户组数据表名
'AUTH_GROUP_ACCESS'=>'think_auth_group_access',//用户-用户组关系表
'AUTH_RULE'=>'think_auth_rule',//权限规则表
'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'));//可设置配置项auth_config,此配置项为数组。
}
}
/**
*检查权限
* @param name string|array需要验证的规则列表,支持逗号分隔的权限规则或索引数组
* @param uid int认证用户的id
* @param string mode执行check的模式
* @param relation string如果为'or'表示满足任一条规则即通过验证;如果为'and'则表示需满足所有规则才能通过验证
* @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);//获取用户需要验证的所有有效规则列表
if(is_string($name)) {
$name=strtolower($name);
$name=strpos($name,',')!== false ?explode(',',$name): array($name);
}
$list= array();//保存验证通过的规则名
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);//解析规则中的param
$intersect=array_intersect_assoc($REQUEST,$param);
$auth=preg_replace('/\?.*$/U','',$auth);
if(in_array($auth,$name)&&$intersect==$param) {//如果节点相符且url参数满足
$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;
}
/**
*根据用户id获取用户组,返回值为数组
* @param uid int用户id
* @return array用户所属的用户组array(
* array('uid'=>'用户id','group_id'=>'用户组id','title'=>'用户组名称','rules'=>'用户组拥有的规则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];
}
/**
*获得权限列表
* @param integer $uid用户id
* @param integer $type
*/
protected functiongetAuthList($uid,$type) {
static$_authList= array();//保存用户验证通过的权限列表
$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();//保存用户所属用户组设置的所有权限规则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,
);
//读取用户组所有权限规则
$rules=Db::table($this->_config['AUTH_RULE'])->where($map)->field('condition,name,url')->select();
//循环规则,判断结果。
$authList= array();//
foreach($rulesas$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) {
$authList[]=strtolower($rule['url']);
}
}else{
//只要存在就记录
$authList[]=strtolower($rule['url']);
}
}
$_authList[$uid.$t]=$authList;
if($this->_config['AUTH_TYPE']==2){
//规则列表结果保存到session
$_SESSION['_AUTH_LIST_'.$uid.$t]=$authList;
}
returnarray_unique($authList);
}
/**
*获得用户资料,根据自己的情况读取数据库
*/
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"); //因为是将认证类作为自己的第三方包写的,所以使用时需要先导入
$auth= newAuth();
$name=Request::instance()->controller().'/'.Request::instance()->action(); //如需要验证Index/index 登录的用户是否有操作该类的权限
$res=$auth->check($name,$uid); //调用验证方法里的验证
if(!$res){
echo'你没有权限';
}else{
echo'登录成功';
}
}