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

<?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];
}
}