Skip to content

Commit 82ee268

Browse files
authored
Create Auth.php
1 parent 32b8ea2 commit 82ee268

File tree

1 file changed

+253
-0
lines changed

1 file changed

+253
-0
lines changed

src/Auth.php

Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
<?php
2+
// +----------------------------------------------------------------------
3+
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
4+
// +----------------------------------------------------------------------
5+
// | Copyright (c) 2011 http://thinkphp.cn All rights reserved.
6+
// +----------------------------------------------------------------------
7+
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
8+
// +----------------------------------------------------------------------
9+
namespace wamkj\thinkphp;
10+
/**
11+
* 权限认证类
12+
* 功能特性:
13+
* 1,是对规则进行认证,不是对节点进行认证。用户可以把节点当作规则名称实现对节点进行认证。
14+
* $auth=new Auth(); $auth->check('规则名称','用户id')
15+
* 2,可以同时对多条规则进行认证,并设置多条规则的关系(or或者and)
16+
* $auth=new Auth(); $auth->check('规则1,规则2','用户id','and')
17+
* 第三个参数为and时表示,用户需要同时具有规则1和规则2的权限。 当第三个参数为or时,表示用户值需要具备其中一个条件即可。默认为or
18+
* 3,一个用户可以属于多个用户组(tp_auth_group_access表 定义了用户所属用户组)。我们需要设置每个用户组拥有哪些规则(tp_auth_group 定义了用户组权限)
19+
*
20+
* 4,支持规则表达式。
21+
* 在tp_auth_rule 表中定义一条规则时,如果type为1, condition字段就可以定义规则表达式。 如定义{score}>5 and {score}<100 表示用户的分数在5-100之间时这条规则才会通过。
22+
*/
23+
24+
//数据库
25+
/*
26+
-- ----------------------------
27+
-- tp_admin,用户表,
28+
-- id:主键,is_admin:是否是管理员
29+
-- ----------------------------
30+
DROP TABLE IF EXISTS `tp_admin`;
31+
CREATE TABLE `tp_admin` (
32+
`id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '管理员ID',
33+
`is_admin` tinyint(1) NOT NULL DEFAULT '0',
34+
`username` varchar(50) NOT NULL DEFAULT '' COMMENT '管理员用户名',
35+
`fullname` varchar(50) NOT NULL DEFAULT '',
36+
`phone` varchar(20) NOT NULL DEFAULT '',
37+
`password_reset_token` varchar(255) NOT NULL DEFAULT '',
38+
`access_token` varchar(32) NOT NULL DEFAULT '',
39+
`email` varchar(255) NOT NULL DEFAULT '' COMMENT '邮箱',
40+
`password` varchar(32) NOT NULL DEFAULT '' COMMENT '管理员密码',
41+
`login_times` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '登陆次数',
42+
`login_ip` varchar(20) NOT NULL DEFAULT '' COMMENT 'IP地址',
43+
`login_time` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '登陆时间',
44+
`last_login_ip` varchar(255) NOT NULL DEFAULT '' COMMENT '上次登陆ip',
45+
`last_login_time` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '上次登陆时间',
46+
`user_agent` varchar(500) NOT NULL DEFAULT '' COMMENT 'user_agent',
47+
`create_time` int(10) unsigned NOT NULL DEFAULT '0',
48+
`update_time` int(10) NOT NULL DEFAULT '0',
49+
`status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '1可用0禁用',
50+
PRIMARY KEY (`id`)
51+
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
52+
-- ----------------------------
53+
-- tp_auth_rule,规则表,
54+
-- id:主键,name:规则唯一标识, title:规则中文名称 status 状态:为1正常,为0禁用,condition:规则表达式,为空表示存在就验证,不为空表示按照条件验证
55+
-- ----------------------------
56+
DROP TABLE IF EXISTS `tp_auth_rule`;
57+
CREATE TABLE `tp_auth_rule` (
58+
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
59+
`name` char(80) NOT NULL DEFAULT '',
60+
`title` char(20) NOT NULL DEFAULT '',
61+
`type` tinyint(1) NOT NULL DEFAULT '1',
62+
`status` tinyint(1) NOT NULL DEFAULT '1',
63+
`condition` char(100) NOT NULL DEFAULT '', # 规则附件条件,满足附加条件的规则,才认为是有效的规则
64+
PRIMARY KEY (`id`),
65+
UNIQUE KEY `name` (`name`)
66+
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
67+
-- ----------------------------
68+
-- tp_auth_group 用户组表,
69+
-- id:主键, title:用户组中文名称, rules:用户组拥有的规则id, 多个规则","隔开,status 状态:为1正常,为0禁用
70+
-- ----------------------------
71+
DROP TABLE IF EXISTS `tp_auth_group`;
72+
CREATE TABLE `tp_auth_group` (
73+
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
74+
`title` char(100) NOT NULL DEFAULT '',
75+
`status` tinyint(1) NOT NULL DEFAULT '1',
76+
`rules` char(80) NOT NULL DEFAULT '',
77+
PRIMARY KEY (`id`)
78+
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
79+
-- ----------------------------
80+
-- tp_auth_group_access 用户组明细表
81+
-- uid:用户id,group_id:用户组id
82+
-- ----------------------------
83+
DROP TABLE IF EXISTS `tp_auth_group_access`;
84+
CREATE TABLE `tp_auth_group_access` (
85+
`uid` mediumint(8) unsigned NOT NULL,
86+
`group_id` mediumint(8) unsigned NOT NULL,
87+
UNIQUE KEY `uid_group_id` (`uid`,`group_id`),
88+
KEY `uid` (`uid`),
89+
KEY `group_id` (`group_id`)
90+
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
91+
*/
92+
93+
class Auth{
94+
95+
//默认配置
96+
protected $_config = array(
97+
'auth_on' => true, // 认证开关
98+
'auth_type' => 1, // 认证方式,1为实时认证;2为登录认证。
99+
'auth_group' => 'auth_group', // 用户组数据表名
100+
'auth_group_access' => 'auth_group_access', // 用户-用户组关系表
101+
'auth_rule' => 'auth_rule', // 权限规则表
102+
'auth_user' => 'admin' // 用户信息表
103+
);
104+
105+
public function __construct() {
106+
$prefix = config('database.prefix');
107+
$this->_config['auth_group'] = $prefix.$this->_config['auth_group'];
108+
$this->_config['auth_rule'] = $prefix.$this->_config['auth_rule'];
109+
$this->_config['auth_user'] = $prefix.$this->_config['auth_user'];
110+
$this->_config['auth_group_access'] = $prefix.$this->_config['auth_group_access'];
111+
if (config('auth.auth_config')) {
112+
//可设置配置项 auth_config, 此配置项为数组。
113+
$this->_config = array_merge($this->_config, config('auth.auth_config'));
114+
}
115+
}
116+
117+
/**
118+
* 检查权限
119+
* @param name string|array 需要验证的规则列表,支持逗号分隔的权限规则或索引数组
120+
* @param uid int 认证用户的id
121+
* @param string mode 执行check的模式
122+
* @param relation string 如果为 'or' 表示满足任一条规则即通过验证;如果为 'and'则表示需满足所有规则才能通过验证
123+
* @return boolean 通过验证返回true;失败返回false
124+
*/
125+
public function check($name, $uid, $type=1, $mode='url', $relation='or') {
126+
if (!$this->_config['auth_on'])
127+
return true;
128+
$authList = $this->getAuthList($uid,$type); //获取用户需要验证的所有有效规则列表
129+
if (is_string($name)) {
130+
$name = strtolower($name);
131+
if (strpos($name, ',') !== false) {
132+
$name = explode(',', $name);
133+
} else {
134+
$name = array($name);
135+
}
136+
}
137+
$list = array(); //保存验证通过的规则名
138+
if ($mode=='url') {
139+
$REQUEST = unserialize( strtolower(serialize($_REQUEST)) );
140+
}
141+
foreach ( $authList as $auth ) {
142+
$query = preg_replace('/^.+\?/U','',$auth);
143+
if ($mode=='url' && $query!=$auth ) {
144+
parse_str($query,$param); //解析规则中的param
145+
$intersect = array_intersect_assoc($REQUEST,$param);
146+
$auth = preg_replace('/\?.*$/U','',$auth);
147+
if ( in_array($auth,$name) && $intersect==$param ) { //如果节点相符且url参数满足
148+
$list[] = $auth ;
149+
}
150+
}else if (in_array($auth , $name)){
151+
$list[] = $auth ;
152+
}
153+
}
154+
if ($relation == 'or' and !empty($list)) {
155+
return true;
156+
}
157+
$diff = array_diff($name, $list);
158+
if ($relation == 'and' and empty($diff)) {
159+
return true;
160+
}
161+
return false;
162+
}
163+
164+
/**
165+
* 根据用户id获取用户组,返回值为数组
166+
* @param uid int 用户id
167+
* @return array 用户所属的用户组 array(
168+
* array('uid'=>'用户id','group_id'=>'用户组id','title'=>'用户组名称','rules'=>'用户组拥有的规则id,多个,号隔开'),
169+
* ...)
170+
*/
171+
public function getGroups($uid) {
172+
static $groups = array();
173+
if (isset($groups[$uid]))
174+
return $groups[$uid];
175+
$user_groups = \think\facade\Db::table($this->_config['auth_group_access'])
176+
->alias('a')
177+
->where("a.uid='$uid' and g.status='1'")
178+
->join($this->_config['auth_group'].' g','a.group_id=g.id')
179+
->field('uid,group_id,title,rules')
180+
->select();
181+
$groups[$uid]=$user_groups?:array();
182+
return $groups[$uid];
183+
}
184+
185+
/**
186+
* 获得权限列表
187+
* @param integer $uid 用户id
188+
* @param integer $type
189+
*/
190+
protected function getAuthList($uid,$type) {
191+
static $_authList = array(); //保存用户验证通过的权限列表
192+
$t = implode(',',(array)$type);
193+
if (isset($_authList[$uid.$t])) {
194+
return $_authList[$uid.$t];
195+
}
196+
if( $this->_config['auth_type']==2 && isset($_SESSION['_auth_list_'.$uid.$t])){
197+
return $_SESSION['_auth_list_'.$uid.$t];
198+
}
199+
200+
//读取用户所属用户组
201+
$groups = $this->getGroups($uid);
202+
$ids = array();//保存用户所属用户组设置的所有权限规则id
203+
foreach ($groups as $g) {
204+
$ids = array_merge($ids, explode(',', trim($g['rules'], ',')));
205+
}
206+
$ids = array_unique($ids);
207+
if (empty($ids)) {
208+
$_authList[$uid.$t] = array();
209+
return array();
210+
}
211+
$map[] = ['id','in',$ids];
212+
$map[] = ['type','=',$type];
213+
$map[] = ['status','=',1];
214+
//读取用户组所有权限规则
215+
$rules = \think\facade\Db::table($this->_config['auth_rule'])->where($map)->field('condition,name')->select();
216+
217+
//循环规则,判断结果。
218+
$authList = array(); //
219+
foreach ($rules as $rule) {
220+
if (!empty($rule['condition'])) { //根据condition进行验证
221+
$user = $this->getUserInfo($uid);//获取用户信息,一维数组
222+
223+
$command = preg_replace('/\{(\w*?)\}/', '$user[\'\\1\']', $rule['condition']);
224+
//dump($command);//debug
225+
@(eval('$condition=(' . $command . ');'));
226+
if ($condition) {
227+
$authList[] = strtolower($rule['name']);
228+
}
229+
} else {
230+
//只要存在就记录
231+
$authList[] = strtolower($rule['name']);
232+
}
233+
}
234+
$_authList[$uid.$t] = $authList;
235+
if($this->_config['auth_type']==2){
236+
//规则列表结果保存到session
237+
$_SESSION['_auth_list_'.$uid.$t]=$authList;
238+
}
239+
return array_unique($authList);
240+
}
241+
242+
/**
243+
* 获得用户资料,根据自己的情况读取数据库
244+
*/
245+
protected function getUserInfo($uid) {
246+
static $userinfo=array();
247+
if(!isset($userinfo[$uid])){
248+
$userinfo[$uid]=\think\facade\Db::table($this->_config['auth_user'])->where('uid',$uid)->find();
249+
}
250+
return $userinfo[$uid];
251+
}
252+
253+
}

0 commit comments

Comments
 (0)