2022-02-27 16:44:12 +00:00
|
|
|
|
<?php
|
|
|
|
|
|
2022-02-27 20:07:40 +00:00
|
|
|
|
namespace ba;
|
2022-02-27 16:44:12 +00:00
|
|
|
|
|
2023-06-25 01:31:03 +00:00
|
|
|
|
use Throwable;
|
2022-02-27 16:44:12 +00:00
|
|
|
|
use think\facade\Db;
|
|
|
|
|
|
|
|
|
|
/**
|
2024-03-11 14:02:35 +00:00
|
|
|
|
* 权限规则类
|
2022-02-27 16:44:12 +00:00
|
|
|
|
*/
|
|
|
|
|
class Auth
|
|
|
|
|
{
|
|
|
|
|
/**
|
|
|
|
|
* 默认配置
|
|
|
|
|
* @var array|string[]
|
|
|
|
|
*/
|
2023-06-25 01:31:03 +00:00
|
|
|
|
protected array $config = [
|
2022-02-27 16:44:12 +00:00
|
|
|
|
'auth_group' => 'admin_group', // 用户组数据表名
|
|
|
|
|
'auth_group_access' => 'admin_group_access', // 用户-用户组关系表
|
2023-06-24 23:04:22 +00:00
|
|
|
|
'auth_rule' => 'admin_rule', // 权限规则表
|
2022-02-27 16:44:12 +00:00
|
|
|
|
];
|
|
|
|
|
|
2022-02-27 20:07:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* 子菜单规则数组
|
|
|
|
|
* @var array
|
|
|
|
|
*/
|
2023-06-25 01:31:03 +00:00
|
|
|
|
protected array $children = [];
|
2022-02-27 19:56:48 +00:00
|
|
|
|
|
2022-02-27 16:44:12 +00:00
|
|
|
|
/**
|
2023-06-25 01:31:03 +00:00
|
|
|
|
* 构造方法
|
2022-02-27 16:44:12 +00:00
|
|
|
|
* @param array $config
|
|
|
|
|
*/
|
2022-10-29 10:56:30 +00:00
|
|
|
|
public function __construct(array $config = [])
|
2022-02-27 16:44:12 +00:00
|
|
|
|
{
|
|
|
|
|
$this->config = array_merge($this->config, $config);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2023-06-25 01:31:03 +00:00
|
|
|
|
* 魔术方法-获取当前配置
|
2022-02-27 16:44:12 +00:00
|
|
|
|
* @param $name
|
2023-06-25 01:31:03 +00:00
|
|
|
|
* @return mixed
|
2022-02-27 16:44:12 +00:00
|
|
|
|
*/
|
2023-06-25 01:31:03 +00:00
|
|
|
|
public function __get($name): mixed
|
2022-02-27 16:44:12 +00:00
|
|
|
|
{
|
|
|
|
|
return $this->config[$name];
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-27 19:56:48 +00:00
|
|
|
|
/**
|
|
|
|
|
* 获取菜单规则列表
|
|
|
|
|
* @access public
|
|
|
|
|
* @param int $uid 用户ID
|
|
|
|
|
* @return array
|
2023-06-25 01:31:03 +00:00
|
|
|
|
* @throws Throwable
|
2022-02-27 19:56:48 +00:00
|
|
|
|
*/
|
2022-10-29 10:56:30 +00:00
|
|
|
|
public function getMenus(int $uid): array
|
2022-02-27 19:56:48 +00:00
|
|
|
|
{
|
2024-03-12 07:44:59 +00:00
|
|
|
|
$this->children = [];
|
|
|
|
|
$originAuthRules = $this->getOriginAuthRules($uid);
|
|
|
|
|
foreach ($originAuthRules as $rule) {
|
2023-06-25 01:31:03 +00:00
|
|
|
|
$this->children[$rule['pid']][] = $rule;
|
2022-02-27 19:56:48 +00:00
|
|
|
|
}
|
2023-06-25 01:31:03 +00:00
|
|
|
|
|
|
|
|
|
// 没有根菜单规则
|
2024-03-11 14:02:35 +00:00
|
|
|
|
if (!isset($this->children[0])) return [];
|
2022-02-27 19:56:48 +00:00
|
|
|
|
|
2023-06-25 01:31:03 +00:00
|
|
|
|
return $this->getChildren($this->children[0]);
|
2022-02-27 19:56:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2023-06-25 01:31:03 +00:00
|
|
|
|
* 获取传递的菜单规则的子规则
|
2022-02-27 19:56:48 +00:00
|
|
|
|
* @param array $rules 菜单规则
|
2023-06-25 01:31:03 +00:00
|
|
|
|
* @return array
|
2022-02-27 19:56:48 +00:00
|
|
|
|
*/
|
2022-10-29 10:56:30 +00:00
|
|
|
|
private function getChildren(array $rules): array
|
2022-02-27 19:56:48 +00:00
|
|
|
|
{
|
|
|
|
|
foreach ($rules as $key => $rule) {
|
2023-06-25 01:31:03 +00:00
|
|
|
|
if (array_key_exists($rule['id'], $this->children)) {
|
|
|
|
|
$rules[$key]['children'] = $this->getChildren($this->children[$rule['id']]);
|
2022-02-27 19:56:48 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $rules;
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-27 16:44:12 +00:00
|
|
|
|
/**
|
|
|
|
|
* 检查是否有某权限
|
|
|
|
|
* @param string $name 菜单规则的 name,可以传递两个,以','号隔开
|
|
|
|
|
* @param int $uid 用户ID
|
|
|
|
|
* @param string $relation 如果出现两个 name,是两个都通过(and)还是一个通过即可(or)
|
|
|
|
|
* @param string $mode 如果不使用 url 则菜单规则name匹配到即通过
|
|
|
|
|
* @return bool
|
2023-06-25 01:31:03 +00:00
|
|
|
|
* @throws Throwable
|
2022-02-27 16:44:12 +00:00
|
|
|
|
*/
|
2022-10-29 10:56:30 +00:00
|
|
|
|
public function check(string $name, int $uid, string $relation = 'or', string $mode = 'url'): bool
|
2022-02-27 16:44:12 +00:00
|
|
|
|
{
|
|
|
|
|
// 获取用户需要验证的所有有效规则列表
|
2023-06-25 01:31:03 +00:00
|
|
|
|
$ruleList = $this->getRuleList($uid);
|
|
|
|
|
if (in_array('*', $ruleList)) {
|
2022-02-27 16:44:12 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-29 10:56:30 +00:00
|
|
|
|
if ($name) {
|
2022-02-27 16:44:12 +00:00
|
|
|
|
$name = strtolower($name);
|
2023-06-25 01:31:03 +00:00
|
|
|
|
if (str_contains($name, ',')) {
|
2022-02-27 16:44:12 +00:00
|
|
|
|
$name = explode(',', $name);
|
|
|
|
|
} else {
|
|
|
|
|
$name = [$name];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$list = []; //保存验证通过的规则名
|
|
|
|
|
if ('url' == $mode) {
|
2022-11-19 09:46:56 +00:00
|
|
|
|
$REQUEST = json_decode(strtolower(json_encode(request()->param(), JSON_UNESCAPED_UNICODE)), true);
|
2022-02-27 16:44:12 +00:00
|
|
|
|
}
|
2023-06-25 01:31:03 +00:00
|
|
|
|
foreach ($ruleList as $rule) {
|
2022-02-27 16:44:12 +00:00
|
|
|
|
$query = preg_replace('/^.+\?/U', '', $rule);
|
|
|
|
|
if ('url' == $mode && $query != $rule) {
|
|
|
|
|
parse_str($query, $param); //解析规则中的param
|
|
|
|
|
$intersect = array_intersect_assoc($REQUEST, $param);
|
|
|
|
|
$rule = preg_replace('/\?.*$/U', '', $rule);
|
|
|
|
|
if (in_array($rule, $name) && $intersect == $param) {
|
|
|
|
|
// 如果节点相符且url参数满足
|
|
|
|
|
$list[] = $rule;
|
|
|
|
|
}
|
2024-06-02 14:39:10 +00:00
|
|
|
|
} elseif (in_array($rule, $name)) {
|
|
|
|
|
$list[] = $rule;
|
2022-02-27 16:44:12 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ('or' == $relation && !empty($list)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
$diff = array_diff($name, $list);
|
|
|
|
|
if ('and' == $relation && empty($diff)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获得权限规则列表
|
|
|
|
|
* @param int $uid 用户id
|
|
|
|
|
* @return array
|
2023-06-25 01:31:03 +00:00
|
|
|
|
* @throws Throwable
|
2022-02-27 16:44:12 +00:00
|
|
|
|
*/
|
2022-10-29 10:56:30 +00:00
|
|
|
|
public function getRuleList(int $uid): array
|
2022-02-27 16:44:12 +00:00
|
|
|
|
{
|
|
|
|
|
// 读取用户规则节点
|
|
|
|
|
$ids = $this->getRuleIds($uid);
|
2024-03-11 14:02:35 +00:00
|
|
|
|
if (empty($ids)) return [];
|
|
|
|
|
|
2024-03-12 07:44:59 +00:00
|
|
|
|
$originAuthRules = $this->getOriginAuthRules($uid);
|
|
|
|
|
|
|
|
|
|
// 用户规则
|
|
|
|
|
$rules = [];
|
|
|
|
|
if (in_array('*', $ids)) {
|
|
|
|
|
$rules[] = "*";
|
|
|
|
|
}
|
|
|
|
|
foreach ($originAuthRules as $rule) {
|
|
|
|
|
$rules[$rule['id']] = strtolower($rule['name']);
|
|
|
|
|
}
|
|
|
|
|
return array_unique($rules);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获得权限规则原始数据
|
|
|
|
|
* @param int $uid 用户id
|
|
|
|
|
* @return array
|
|
|
|
|
* @throws Throwable
|
|
|
|
|
*/
|
|
|
|
|
public function getOriginAuthRules(int $uid): array
|
|
|
|
|
{
|
|
|
|
|
$ids = $this->getRuleIds($uid);
|
|
|
|
|
if (empty($ids)) return [];
|
|
|
|
|
|
2024-06-24 16:33:16 +00:00
|
|
|
|
$where = [];
|
|
|
|
|
$where[] = ['status', '=', '1'];
|
|
|
|
|
// 如果没有 * 则只获取用户拥有的规则
|
|
|
|
|
if (!in_array('*', $ids)) {
|
|
|
|
|
$where[] = ['id', 'in', $ids];
|
|
|
|
|
}
|
|
|
|
|
$rules = Db::name($this->config['auth_rule'])
|
|
|
|
|
->withoutField(['remark', 'status', 'weigh', 'update_time', 'create_time'])
|
|
|
|
|
->where($where)
|
|
|
|
|
->order('weigh desc,id asc')
|
|
|
|
|
->select()
|
|
|
|
|
->toArray();
|
|
|
|
|
foreach ($rules as $key => $rule) {
|
|
|
|
|
if (!empty($rule['keepalive'])) {
|
|
|
|
|
$rules[$key]['keepalive'] = $rule['name'];
|
2024-03-11 14:02:35 +00:00
|
|
|
|
}
|
2022-02-27 16:44:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-06-24 16:33:16 +00:00
|
|
|
|
return $rules;
|
2022-02-27 16:44:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取权限规则ids
|
2022-10-29 10:56:30 +00:00
|
|
|
|
* @param int $uid
|
2022-02-27 16:44:12 +00:00
|
|
|
|
* @return array
|
2023-06-25 01:31:03 +00:00
|
|
|
|
* @throws Throwable
|
2022-02-27 16:44:12 +00:00
|
|
|
|
*/
|
2022-10-29 10:56:30 +00:00
|
|
|
|
public function getRuleIds(int $uid): array
|
2022-02-27 16:44:12 +00:00
|
|
|
|
{
|
|
|
|
|
// 用户的组别和规则ID
|
|
|
|
|
$groups = $this->getGroups($uid);
|
|
|
|
|
$ids = [];
|
|
|
|
|
foreach ($groups as $g) {
|
|
|
|
|
$ids = array_merge($ids, explode(',', trim($g['rules'], ',')));
|
|
|
|
|
}
|
2022-08-23 16:27:21 +00:00
|
|
|
|
return array_unique($ids);
|
2022-02-27 16:44:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取用户所有分组和对应权限规则
|
2022-10-29 10:56:30 +00:00
|
|
|
|
* @param int $uid
|
2022-02-27 16:44:12 +00:00
|
|
|
|
* @return array
|
2023-06-25 01:31:03 +00:00
|
|
|
|
* @throws Throwable
|
2022-02-27 16:44:12 +00:00
|
|
|
|
*/
|
2022-10-29 10:56:30 +00:00
|
|
|
|
public function getGroups(int $uid): array
|
2022-02-27 16:44:12 +00:00
|
|
|
|
{
|
2024-03-12 07:44:59 +00:00
|
|
|
|
$dbName = $this->config['auth_group_access'] ?: 'user';
|
2022-06-19 16:07:34 +00:00
|
|
|
|
if ($this->config['auth_group_access']) {
|
2024-03-12 07:44:59 +00:00
|
|
|
|
$userGroups = Db::name($dbName)
|
2022-06-19 16:07:34 +00:00
|
|
|
|
->alias('aga')
|
|
|
|
|
->join($this->config['auth_group'] . ' ag', 'aga.group_id = ag.id', 'LEFT')
|
|
|
|
|
->field('aga.uid,aga.group_id,ag.id,ag.pid,ag.name,ag.rules')
|
2022-10-29 10:56:30 +00:00
|
|
|
|
->where("aga.uid='$uid' and ag.status='1'")
|
2023-06-25 01:31:03 +00:00
|
|
|
|
->select()
|
|
|
|
|
->toArray();
|
2022-06-19 16:07:34 +00:00
|
|
|
|
} else {
|
2024-03-12 07:44:59 +00:00
|
|
|
|
$userGroups = Db::name($dbName)
|
2022-06-19 16:07:34 +00:00
|
|
|
|
->alias('u')
|
|
|
|
|
->join($this->config['auth_group'] . ' ag', 'u.group_id = ag.id', 'LEFT')
|
|
|
|
|
->field('u.id as uid,u.group_id,ag.id,ag.name,ag.rules')
|
2022-10-29 10:56:30 +00:00
|
|
|
|
->where("u.id='$uid' and ag.status='1'")
|
2023-06-25 01:31:03 +00:00
|
|
|
|
->select()
|
|
|
|
|
->toArray();
|
2022-06-19 16:07:34 +00:00
|
|
|
|
}
|
2022-02-27 16:44:12 +00:00
|
|
|
|
|
2024-06-24 16:33:16 +00:00
|
|
|
|
return $userGroups;
|
2022-02-27 16:44:12 +00:00
|
|
|
|
}
|
|
|
|
|
}
|