188 lines
5.6 KiB
PHP
188 lines
5.6 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
namespace ba;
|
||
|
||
use Throwable;
|
||
use support\think\Db;
|
||
|
||
/**
|
||
* 权限规则类(Webman 迁移版)
|
||
*/
|
||
class Auth
|
||
{
|
||
protected array $config = [
|
||
'auth_group' => 'admin_group',
|
||
'auth_group_access' => 'admin_group_access',
|
||
'auth_rule' => 'admin_rule',
|
||
];
|
||
|
||
protected array $children = [];
|
||
|
||
public function __construct(array $config = [])
|
||
{
|
||
$this->config = array_merge($this->config, $config);
|
||
}
|
||
|
||
public function __get($name): mixed
|
||
{
|
||
return $this->config[$name] ?? null;
|
||
}
|
||
|
||
public function getMenus(int $uid): array
|
||
{
|
||
$this->children = [];
|
||
$originAuthRules = $this->getOriginAuthRules($uid);
|
||
foreach ($originAuthRules as $rule) {
|
||
$this->children[$rule['pid']][] = $rule;
|
||
}
|
||
|
||
if (!isset($this->children[0])) {
|
||
return [];
|
||
}
|
||
|
||
return $this->getChildren($this->children[0]);
|
||
}
|
||
|
||
private function getChildren(array $rules): array
|
||
{
|
||
foreach ($rules as $key => $rule) {
|
||
if (array_key_exists($rule['id'], $this->children)) {
|
||
$rules[$key]['children'] = $this->getChildren($this->children[$rule['id']]);
|
||
}
|
||
}
|
||
return $rules;
|
||
}
|
||
|
||
public function check(string $name, int $uid, string $relation = 'or', string $mode = 'url'): bool
|
||
{
|
||
$ruleList = $this->getRuleList($uid);
|
||
if (in_array('*', $ruleList)) {
|
||
return true;
|
||
}
|
||
|
||
if ($name) {
|
||
$name = strtolower($name);
|
||
$name = str_contains($name, ',') ? explode(',', $name) : [$name];
|
||
}
|
||
$list = [];
|
||
$requestParams = [];
|
||
if ($mode === 'url' && function_exists('request')) {
|
||
$req = request();
|
||
$requestParams = $req ? array_merge($req->get(), $req->post()) : [];
|
||
$requestParams = json_decode(strtolower(json_encode($requestParams, JSON_UNESCAPED_UNICODE)), true) ?? [];
|
||
}
|
||
|
||
foreach ($ruleList as $rule) {
|
||
$query = preg_replace('/^.+\?/U', '', $rule);
|
||
if ($mode === 'url' && $query !== $rule) {
|
||
parse_str($query, $param);
|
||
$intersect = array_intersect_assoc($requestParams, $param);
|
||
$rule = preg_replace('/\?.*$/U', '', $rule);
|
||
if (in_array($rule, $name) && $intersect == $param) {
|
||
$list[] = $rule;
|
||
}
|
||
} elseif (in_array($rule, $name)) {
|
||
$list[] = $rule;
|
||
} else {
|
||
// 仅勾选父级菜单(如 auth/admin)时,允许访问子路径(auth/admin/index、add 等)
|
||
$baseRule = preg_replace('/\?.*$/U', '', $rule);
|
||
foreach ((array) $name as $n) {
|
||
if ($baseRule !== '' && str_starts_with((string) $n, $baseRule . '/')) {
|
||
$list[] = $rule;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if ($relation === 'or' && !empty($list)) {
|
||
return true;
|
||
}
|
||
$diff = array_diff($name, $list);
|
||
if ($relation === 'and' && empty($diff)) {
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
public function getRuleList(int $uid): array
|
||
{
|
||
$ids = $this->getRuleIds($uid);
|
||
if (empty($ids)) {
|
||
return [];
|
||
}
|
||
|
||
$originAuthRules = $this->getOriginAuthRules($uid);
|
||
$rules = [];
|
||
if (in_array('*', $ids)) {
|
||
$rules[] = '*';
|
||
}
|
||
foreach ($originAuthRules as $rule) {
|
||
$rules[$rule['id']] = strtolower($rule['name']);
|
||
}
|
||
return array_unique($rules);
|
||
}
|
||
|
||
public function getOriginAuthRules(int $uid): array
|
||
{
|
||
$ids = $this->getRuleIds($uid);
|
||
if (empty($ids)) {
|
||
return [];
|
||
}
|
||
|
||
$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'];
|
||
}
|
||
}
|
||
|
||
return $rules;
|
||
}
|
||
|
||
public function getRuleIds(int $uid): array
|
||
{
|
||
$groups = $this->getGroups($uid);
|
||
$ids = [];
|
||
foreach ($groups as $g) {
|
||
$ids = array_merge($ids, explode(',', trim($g['rules'] ?? '', ',')));
|
||
}
|
||
return array_unique($ids);
|
||
}
|
||
|
||
public function getGroups(int $uid): array
|
||
{
|
||
$dbName = $this->config['auth_group_access'] ?: 'user';
|
||
if ($this->config['auth_group_access']) {
|
||
$userGroups = Db::name($dbName)
|
||
->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')
|
||
->where("aga.uid='$uid' and ag.status='1'")
|
||
->select()
|
||
->toArray();
|
||
} else {
|
||
$userGroups = Db::name($dbName)
|
||
->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')
|
||
->where("u.id='$uid' and ag.status='1'")
|
||
->select()
|
||
->toArray();
|
||
}
|
||
|
||
return $userGroups;
|
||
}
|
||
}
|