You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
438 lines
14 KiB
438 lines
14 KiB
<?php
|
|
/**
|
|
* Created by 花密欧团队.
|
|
* User: 云掌.帮德
|
|
* Date: 2020/3/8 22:30
|
|
* Desc:
|
|
*/
|
|
|
|
namespace auth;
|
|
|
|
use service\ActionLog;
|
|
use think\facade\Db;
|
|
use think\facade\Config;
|
|
use think\facade\Request;
|
|
use think\Session;
|
|
|
|
class PermissAuth
|
|
{
|
|
|
|
/**
|
|
* @var object 对象实例
|
|
*/
|
|
protected static $instance = null;
|
|
/**
|
|
* 当前请求实例
|
|
* @var Request
|
|
*/
|
|
protected $request;
|
|
|
|
protected $site_id = 0; //多站点id
|
|
|
|
//默认配置
|
|
protected $config = [
|
|
'auth_on' => 1, // 权限开关
|
|
'auth_type' => 1, // 认证方式,1为实时认证;2为登录认证。
|
|
'auth_group' => 'auth_group', // 用户组数据表名
|
|
'auth_group_access' => 'auth_group_access', // 用户-用户组关系表
|
|
'auth_rule' => 'auth_rule', // 权限规则表
|
|
'auth_user' => 'user', // 用户信息表
|
|
];
|
|
|
|
/**
|
|
* 类架构函数
|
|
* Auth constructor.
|
|
*/
|
|
private function __construct()
|
|
{
|
|
//可设置配置项 auth, 此配置项为数组。
|
|
if ($auth = Config::get('auth')) {
|
|
$this->config = array_merge($this->config, $auth);
|
|
}
|
|
// 初始化request
|
|
$this->request = Request::instance();
|
|
|
|
if (!defined('SITE_ID')) {
|
|
return false;
|
|
}
|
|
$this->site_id = SITE_ID;
|
|
|
|
|
|
}
|
|
|
|
public function __clone()
|
|
{
|
|
// TODO: Implement __clone() method.
|
|
}
|
|
|
|
/**
|
|
* 初始化
|
|
* @access public
|
|
* @param array $options 参数
|
|
* @return \think\Request
|
|
*/
|
|
public static function getInstance($options = [])
|
|
{
|
|
if (is_null(self::$instance)) {
|
|
self::$instance = new self($options);
|
|
}
|
|
return self::$instance;
|
|
}
|
|
|
|
/**
|
|
* 检查权限
|
|
* @param $name string|array 需要验证的规则列表,支持逗号分隔的权限规则或索引数组
|
|
* @param $uid int 认证用户的id
|
|
* @param int $type 认证类型
|
|
* @param string $mode 执行check的模式
|
|
* @param string $relation 如果为 'or' 表示满足任一条规则即通过验证;如果为 'and'则表示需满足所有规则才能通过验证
|
|
* @return bool 通过验证返回true;失败返回false
|
|
*/
|
|
public function check($name, $uid, $type = 1, $mode = 'url', $relation = 'or')
|
|
{
|
|
if (!$this->config['auth_on']) {
|
|
return true;
|
|
}
|
|
|
|
//判断是否配置文件中放行的url
|
|
if (in_array(strtolower($name), array_keys(array_change_key_case($this->config['auth_filter_model'])))) {
|
|
return true;
|
|
}
|
|
// 获取用户需要验证的所有有效规则列表
|
|
$authList = $this->getAuthList($uid, $type, false, 2);
|
|
if (is_string($name)) {
|
|
$name = strtolower($name);
|
|
if (strpos($name, ',') !== false) {
|
|
$name = explode(',', $name);
|
|
} else {
|
|
$name = [$name];
|
|
}
|
|
}
|
|
$list = []; //保存验证通过的规则名
|
|
if ('url' == $mode) {
|
|
$REQUEST = unserialize(strtolower(serialize($this->request->param())));
|
|
}
|
|
|
|
foreach ($authList as $auth) {
|
|
$query = preg_replace('/^.+\?/U', '', $auth);
|
|
if ('url' == $mode && $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 ('or' == $relation && !empty($list)) {
|
|
return true;
|
|
}
|
|
$diff = array_diff($name, $list);
|
|
if ('and' == $relation && empty($diff)) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* 根据用户id获取用户组,返回值为数组
|
|
* @param $uid int 用户id
|
|
* @return array 用户所属的用户组 array(
|
|
* array('uid'=>'用户id','group_id'=>'用户组id','title'=>'用户组名称','rules'=>'用户组拥有的规则id,多个,号隔开'),
|
|
* ...)
|
|
*/
|
|
public function getUserGroups(int $uid = 0)
|
|
{
|
|
static $groups = [];
|
|
if (isset($groups[$uid])) {
|
|
return $groups[$uid];
|
|
}
|
|
// 转换表名
|
|
$auth_group_access = $this->config['auth_group_access'];
|
|
$auth_group = $this->config['auth_group'];
|
|
// 执行查询
|
|
$user_groups = Db::view([$auth_group_access => $auth_group_access], 'uid,group_id')
|
|
->view([$auth_group => $auth_group], 'id,title,role_code,rules', "{$auth_group_access}.group_id={$auth_group}.id", 'LEFT')
|
|
->where("{$auth_group_access}.uid='{$uid}' and {$auth_group}.status='1'")
|
|
->select()->toArray();
|
|
$groups[$uid] = $user_groups ?: [];
|
|
|
|
return $groups[$uid];
|
|
}
|
|
|
|
/**
|
|
* 获取系统所有角色
|
|
* @return \think\Collection
|
|
* @throws \think\db\exception\DataNotFoundException
|
|
* @throws \think\db\exception\DbException
|
|
* @throws \think\db\exception\ModelNotFoundException
|
|
*/
|
|
public function getGroups()
|
|
{
|
|
$title = $this->request->param('title', '');
|
|
$role_code = $this->request->param('role_code', '');
|
|
$page = $this->request->param('page', 1, 'intval');
|
|
$limit = $this->request->param('limit', 10, 'intval');
|
|
$_db = Db::table($this->config['auth_group']);
|
|
$_db->where('site_id', $this->site_id);
|
|
//搜索角色名称
|
|
empty($title) ? '' : $_db->where('title', 'like', '%' . $title . '%');
|
|
empty($role_code) ? '' : $_db->where('role_code', 'like', '%' . $role_code . '%');
|
|
|
|
$_groups = $_db->where('type', 1)->page($page, $limit)->select();
|
|
if (!$_groups->isEmpty()) {
|
|
$_groups = $_groups->toArray();
|
|
array_walk($_groups, function (&$v, $k) {
|
|
$v['update_time'] = date('Y-m-d H:i:s', $v['update_time']);
|
|
$v['create_time'] = date('Y-m-d H:i:s', $v['create_time']);
|
|
});
|
|
}
|
|
return $_groups;
|
|
}
|
|
|
|
/**
|
|
* 根据用户角色组ID获取用户角色组权限菜单
|
|
* @param string $id
|
|
* @return array|void
|
|
* @throws \think\db\exception\DataNotFoundException
|
|
* @throws \think\db\exception\DbException
|
|
* @throws \think\db\exception\ModelNotFoundException
|
|
*/
|
|
public function getGroupRule(int $id = 0)
|
|
{
|
|
if (!$id) {
|
|
return;
|
|
}
|
|
$_db = Db::table($this->config['auth_group']);
|
|
$_db->where('site_id', $this->site_id);
|
|
$_data = $_db->field('rules')->find($id);
|
|
if (empty($_data)) {
|
|
return;
|
|
}
|
|
if(SITE_ID == 1){
|
|
$_rules = Db::table($this->config['auth_rule'])->select();
|
|
}else{
|
|
$_rules = Db::table($this->config['auth_rule'])->where('is_manager_use',0)->select();
|
|
}
|
|
|
|
|
|
$_data = explode(',', $_data['rules']);
|
|
if (!$_rules->isEmpty()) {
|
|
$_rules = $_rules->toArray();
|
|
array_walk($_rules, function (&$v) use ($_data) {
|
|
$v['title'] = $v['name'];
|
|
$v['checked'] = in_array($v['id'], $_data) ? true : false;
|
|
$v['children'] = null;
|
|
$v['open'] = true;
|
|
});
|
|
return $_rules;
|
|
}
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* 添加用户到用户角色组关系
|
|
* @param array $_data
|
|
* @return int|string
|
|
*/
|
|
public function addUserGroupAccess(int $user_id, array $_data = [])
|
|
{
|
|
|
|
if (empty($_data) || empty($user_id)) {
|
|
return true;
|
|
}
|
|
$_db = Db::table($this->config['auth_group_access']);
|
|
//添加之前先删除已有的用户角色所有权限
|
|
$_db->where('site_id', $this->site_id)->where('uid', $user_id)->delete();
|
|
|
|
foreach ($_data as $k => $v) {
|
|
$insert_data[$k]['site_id'] = $this->site_id;
|
|
$insert_data[$k]['uid'] = $user_id;
|
|
$insert_data[$k]['group_id'] = $v;
|
|
$insert_data[$k]['update_time'] = $insert_data[$k]['create_time'] = time();
|
|
}
|
|
$affected = $_db->strict(false)->insertAll($insert_data);
|
|
return $affected;
|
|
}
|
|
|
|
/**
|
|
* 添加权限菜单用户角色组
|
|
* @param array $_data
|
|
* @return int|string
|
|
*/
|
|
public function addGroupRule(int $role_id = 0, string $menu_id = '')
|
|
{
|
|
$_data['site_id'] = $this->site_id;
|
|
$_data['update_time'] = time();
|
|
$_data['rules'] = $menu_id;
|
|
$_db = Db::table($this->config['auth_group']);
|
|
$_db->where('id', $role_id);
|
|
$affected = $_db->strict(false)->save($_data);
|
|
ActionLog::getInstance()->write($_data, [], $_db->getLastSql());
|
|
return $affected;
|
|
}
|
|
|
|
/**
|
|
* 添加系统用户角色组
|
|
* @param array $_data
|
|
* @return int|string
|
|
*/
|
|
public function addGroup(array $_data = [])
|
|
{
|
|
$_data['site_id'] = $this->site_id;
|
|
$_data['update_time'] = $_data['create_time'] = time();
|
|
$_db = Db::table($this->config['auth_group']);
|
|
$insert_id = $_db->strict(false)->insertGetId($_data);
|
|
ActionLog::getInstance()->write($_data, [], $_db->getLastSql());
|
|
return $insert_id;
|
|
}
|
|
|
|
/**
|
|
* 修改系统用户角色组
|
|
* @param array $_data
|
|
* @return int|string
|
|
*/
|
|
public function editGroup(array $_data = [])
|
|
{
|
|
$_data['site_id'] = $this->site_id;
|
|
$_data['update_time'] = time();
|
|
$_db = Db::table($this->config['auth_group']);
|
|
$affected = $_db->strict(false)->save($_data);
|
|
ActionLog::getInstance()->write($_data, [], $_db->getLastSql());
|
|
return $affected;
|
|
}
|
|
|
|
/**
|
|
* 更改用户角色组状态
|
|
* @param array $ids
|
|
* @return int
|
|
* @throws \think\db\exception\DbException
|
|
*/
|
|
public function statusGroup(string $ids = '', int $status = 1)
|
|
{
|
|
$_op = Db::table($this->config['auth_group']);
|
|
$ids = explode(',', $ids);
|
|
$_op->where('site_id', SITE_ID);
|
|
$_op->where('id', 'in', $ids);
|
|
$affected = $_op->update(['status' => $status]);
|
|
ActionLog::getInstance()->write($ids, [], $_op->getLastSql());
|
|
return $affected;
|
|
}
|
|
|
|
/**
|
|
* 删除系统用户角色组
|
|
* @param array $ids
|
|
* @return int
|
|
* @throws \think\db\exception\DbException
|
|
*/
|
|
public function deleteGroup($ids = [])
|
|
{
|
|
$_op = Db::table($this->config['auth_group']);
|
|
$ids = explode(',', $ids);
|
|
$_op->where('site_id', SITE_ID);
|
|
$affected = $_op->where('id', 'in', $ids)->delete();
|
|
ActionLog::getInstance()->write($ids, [], $_op->getLastSql());
|
|
return $affected;
|
|
}
|
|
|
|
/**
|
|
* 获得权限列表
|
|
* @param integer $uid 用户id
|
|
* @param integer $type
|
|
* @param integer $allfield 是否获取rule多字段,默认为false
|
|
* @param integer $menu_type 0:获取菜单(默认) 1:获取按钮 2:获取所有
|
|
* @return array
|
|
*/
|
|
public function getAuthList($uid = 0, $type = [], $allfield = false, $menu_type = 0)
|
|
{
|
|
$uid = empty($uid) ? UID : $uid;
|
|
|
|
static $_authList = []; //保存用户验证通过的权限列表
|
|
$t = implode(',', (array)$type);
|
|
if (isset($_authList[$uid . $t])) {
|
|
return $_authList[$uid . $t];
|
|
}
|
|
if (2 == $this->config['auth_type'] && Session::has('_auth_list_' . $uid . $t)) {
|
|
return Session::get('_auth_list_' . $uid . $t);
|
|
}
|
|
//读取用户所属用户组
|
|
$groups = $this->getUserGroups($uid);
|
|
$ids = []; //保存用户所属用户组设置的所有权限规则id
|
|
foreach ($groups as $g) {
|
|
$ids = array_merge($ids, explode(',', trim($g['rules'], ',')));
|
|
}
|
|
$ids = array_unique($ids);
|
|
if (empty($ids)) {
|
|
$_authList[$uid . $t] = [];
|
|
return [];
|
|
}
|
|
$map = [
|
|
'type' => $type,
|
|
'status' => 1,
|
|
];
|
|
$menu_type == 2 ? '' : $map['menu_type'] = $menu_type; //默认获取所有
|
|
config('app.app_debug') ?: $map['is_dev'] = 0;//开发者模式
|
|
|
|
//读取用户组所有权限规则
|
|
$_op = Db::table($this->config['auth_rule']);
|
|
$_op->where($map)->where('id', 'in', $ids)->where('delete_time', null);
|
|
$rules = $_op->order('sort DESC,create_time DESC')->select();
|
|
//$rules = Db::name($this->config['auth_rule'])->where($map)->field('condition,model_name')->select()->toArray();
|
|
//循环规则,判断结果。
|
|
$authList = []; //
|
|
foreach ($rules as $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) {
|
|
if ($allfield) {
|
|
$rule['show'] = empty($rule['show']) ? false : true; //前端需要
|
|
$authList[] = $rule;
|
|
} else {
|
|
$authList[] = strtolower($rule['model_name']);
|
|
}
|
|
}
|
|
} else {
|
|
//只要存在就记录
|
|
if ($allfield) {
|
|
$authList[] = $rule;
|
|
} else {
|
|
$authList[] = strtolower($rule['model_name']);
|
|
}
|
|
}
|
|
}
|
|
$_authList[$uid . $t] = $authList;
|
|
if (2 == $this->config['auth_type']) {
|
|
//规则列表结果保存到session
|
|
//Session::set('_auth_list_' . $uid . $t, $authList);
|
|
}
|
|
return array_unique($authList, SORT_REGULAR);
|
|
}
|
|
|
|
/**
|
|
* 获得用户资料,根据自己的情况读取数据库
|
|
*/
|
|
protected function getUserInfo($uid)
|
|
{
|
|
static $userinfo = [];
|
|
|
|
$user = Db::table($this->config['auth_user']);
|
|
// 获取用户表主键
|
|
$_pk = is_string($user->getPk()) ? $user->getPk() : 'uid';
|
|
if (!isset($userinfo[$uid])) {
|
|
$userinfo[$uid] = $user->where($_pk, $uid)->find();
|
|
}
|
|
|
|
return $userinfo[$uid];
|
|
}
|
|
|
|
}
|