权限管理与测试

This commit is contained in:
zimoyin
2026-04-03 16:21:28 +08:00
parent 673c83109f
commit 76e9f24aa7
11 changed files with 2855 additions and 20 deletions
+143 -20
View File
@@ -2,10 +2,11 @@
namespace plugin\admin\app\common;
use Illuminate\Database\Eloquent\Builder;
use InvalidArgumentException;
use plugin\admin\app\model\OpmMwPermissionRule;
use support\Db;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Query\Builder as QueryBuilder;
/**
* 数据权限规则服务类
@@ -62,40 +63,75 @@ class DataPermissionService
* 3. 收集查询中所有表别名;
* 4. 逐条应用权限规则;
*
* @param Builder|string $query 查询对象
* @return Builder
* @param QueryBuilder|EloquentBuilder $query 查询对象
* @return QueryBuilder|EloquentBuilder
*/
public function apply(Builder|string $query): Builder
public function apply(QueryBuilder|EloquentBuilder $query): QueryBuilder|EloquentBuilder
{
// 兼容传入 Builder 的情况;这里统一取底层 Query Builder
$baseQuery = $query->getQuery();
// 统一拿 baseQuery(核心修复点)
if ($query instanceof EloquentBuilder) {
$baseQuery = $query->getQuery();
$tableRaw = $query->getModel()->getTable();
} else {
$baseQuery = $query;
$tableRaw = $query->from;
}
// 解析主表名和主表别名,例如:table as t => [table, t]
[$fromTable, $fromAlias] = $this->parseTableAlias((string)($baseQuery->from ?? ''));
// 解析主表 & 别
[$fromTable, $fromAlias] = $this->parseTableAlias((string)($tableRaw ?? ''));
// 如果无法识别主表,直接返回,不处理
if ($fromTable === '') {
return $query;
}
// 加载该主表对应的启用规则
// 加载规则
$rules = $this->loadRules($fromTable);
// 没有规则则不做任何限制
if (empty($rules)) {
return $query;
}
// 获取查询里所有表别名映射,后续用于拼字段
// 获取所有表别名
$tableAliases = $this->getAllTableAliases($baseQuery);
// 逐条应用规则
// 应用规则
foreach ($rules as $rule) {
$query = $this->applySingleRule($query, $rule, $fromAlias, $tableAliases);
}
return $query;
}
// public function apply(EloquentBuilder $query): Builder
// {
// // 兼容传入 Builder 的情况;这里统一取底层 Query Builder
// $baseQuery = $query->getQuery();
//
// // 解析主表名和主表别名,例如:table as t => [table, t]
// [$fromTable, $fromAlias] = $this->parseTableAlias((string)($baseQuery->from ?? ''));
//
// // 如果无法识别主表,直接返回,不处理
// if ($fromTable === '') {
// return $query;
// }
//
// // 加载该主表对应的启用规则
// $rules = $this->loadRules($fromTable);
//
// // 没有规则则不做任何限制
// if (empty($rules)) {
// return $query;
// }
//
// // 获取查询里所有表的别名映射,后续用于拼字段
// $tableAliases = $this->getAllTableAliases($baseQuery);
//
// // 逐条应用规则
// foreach ($rules as $rule) {
// $query = $this->applySingleRule($query, $rule, $fromAlias, $tableAliases);
// }
//
// return $query;
// }
/**
* 加载指定表的启用权限规则
@@ -131,18 +167,18 @@ class DataPermissionService
* 5. 得到完整字段名;
* 6. 根据 action 生成 where 条件。
*
* @param Builder $query 查询对象
* @param QueryBuilder|EloquentBuilder $query 查询对象
* @param array $rule 单条规则
* @param string $mainAlias 主表别名
* @param array $tableAliases 查询内所有表别名映射
* @return Builder
* @return QueryBuilder|EloquentBuilder
*/
protected function applySingleRule(
Builder $query,
QueryBuilder|EloquentBuilder $query,
array $rule,
string $mainAlias,
array $tableAliases
): Builder
): QueryBuilder|EloquentBuilder
{
$field = trim((string)($rule['field'] ?? ''));
$adminAttr = trim((string)($rule['admin_attr'] ?? ''));
@@ -197,6 +233,66 @@ class DataPermissionService
return $this->buildCondition($query, $fullField, $action, $resolvedValues[0]);
}
// protected function applySingleRule(
// Builder $query,
// array $rule,
// string $mainAlias,
// array $tableAliases
// ): Builder
// {
// $field = trim((string)($rule['field'] ?? ''));
// $adminAttr = trim((string)($rule['admin_attr'] ?? ''));
// $adminAttrMap = trim((string)($rule['admin_attr_map'] ?? ''));
// $action = strtolower(trim((string)($rule['action'] ?? 'in')));
// $fieldTable = trim((string)($rule['field_table'] ?? ''));
//
// // 规则字段或管理员属性为空,视为无效规则,直接跳过
// if ($field === '' || $adminAttr === '') {
// return $query;
// }
//
// // 校验字段写法是否合法
// $this->validateFieldPath($field, '规则字段');
//
// // 如果配置了字段所属表,也要校验
// if ($fieldTable !== '') {
// $this->validateIdentifierPath($fieldTable, '字段所属表');
// }
//
// // 取管理员对应属性值
// $rawValue = $this->admin[$adminAttr] ?? '';
//
// // * 表示不受限制
// if ($rawValue === '*') {
// return $query;
// }
//
// // 解析管理员属性值,必要时通过映射转换成目标值
// $resolvedValues = $this->resolveAdminAttrValue($rawValue, $adminAttrMap);
//
// // 如果最终解析不到任何可用值,则直接返回空结果
// if (empty($resolvedValues) && !in_array('0', $resolvedValues, true)) {
// return $query->whereRaw('1 = 0');
// }
//
// // 获取规则字段的完整字段名,如 dept.id / t.organ_id
// $fullField = $this->getFullFieldName($field, $mainAlias, $tableAliases, $fieldTable);
//
// // in / not in 这类操作符需要数组值
// if ($this->isArrayOperator($action)) {
// return $this->buildCondition($query, $fullField, $action, $resolvedValues);
// }
//
// // 单值操作符只能对应一个结果,否则说明配置有问题
// if (count($resolvedValues) !== 1) {
// throw new InvalidArgumentException(
// "规则配置错误:操作符 {$action} 只能对应单个值,但当前解析出 " . count($resolvedValues) . " 个值"
// );
// }
//
// return $this->buildCondition($query, $fullField, $action, $resolvedValues[0]);
// }
/**
* 解析管理员属性值
*
@@ -293,13 +389,13 @@ class DataPermissionService
* 1. 数组型条件:in / not in
* 2. 单值条件:= / > / < / like / is null 等
*
* @param Builder $query 查询对象
* @param QueryBuilder|EloquentBuilder $query 查询对象
* @param string $field 完整字段名
* @param string $action 操作符
* @param mixed $value 条件值
* @return Builder
* @return QueryBuilder|EloquentBuilder
*/
protected function buildCondition(Builder $query, string $field, string $action, $value): Builder
protected function buildCondition(QueryBuilder|EloquentBuilder $query, string $field, string $action, $value): QueryBuilder|EloquentBuilder
{
// 数组条件
if (is_array($value)) {
@@ -326,6 +422,33 @@ class DataPermissionService
};
}
// protected function buildCondition(Builder $query, string $field, string $action, $value): Builder
// {
// // 数组条件
// if (is_array($value)) {
// return match ($action) {
// 'in' => $query->whereIn($field, $value),
// 'not in', '<>in' => $query->whereNotIn($field, $value),
// default => throw new InvalidArgumentException("不支持的数组操作符:{$action}"),
// };
// }
//
// // 单值条件
// return match ($action) {
// '=', 'eq' => $query->where($field, '=', $value),
// '>', 'gt' => $query->where($field, '>', $value),
// '<', 'lt' => $query->where($field, '<', $value),
// '>=', 'gte' => $query->where($field, '>=', $value),
// '<=', 'lte' => $query->where($field, '<=', $value),
// '<>', '!=', 'ne' => $query->where($field, '<>', $value),
// 'like' => $query->where($field, 'like', $this->normalizeLikeValue((string)$value)),
// 'not like' => $query->where($field, 'not like', $this->normalizeLikeValue((string)$value)),
// 'is null' => $query->whereNull($field),
// 'is not null' => $query->whereNotNull($field),
// default => throw new InvalidArgumentException("不支持的操作符:{$action}"),
// };
// }
/**
* 获取完整字段名
*