Skip to content

Commit

Permalink
feat: implement data permission rules and context management with cac…
Browse files Browse the repository at this point in the history
…hing support
  • Loading branch information
zds-s committed Mar 12, 2025
1 parent c41a31b commit aea2d49
Show file tree
Hide file tree
Showing 24 changed files with 664 additions and 81 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public function __construct(
public function pageList(): Result
{
return $this->success([
'list' => $this->service->getList($this->getRequestData())
'list' => $this->service->getList($this->getRequestData()),
]);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,4 +118,4 @@ public function delete(): Result
$this->service->deleteById($this->getRequestData());
return $this->success();
}
}
}
2 changes: 1 addition & 1 deletion app/Http/Admin/Request/Permission/PositionRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,4 @@ public function attributes(): array
'dept_id' => '部门ID',
];
}
}
}
53 changes: 36 additions & 17 deletions app/Library/DataPermission/Aspects/DataScopeAspect.php
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
<?php

declare(strict_types=1);
/**
* This file is part of MineAdmin.
*
* @link https://www.mineadmin.com
* @document https://doc.mineadmin.com
* @contact [email protected]
* @license https://github.com/mineadmin/MineAdmin/blob/master/LICENSE
*/

namespace App\Library\DataPermission\Aspects;

use App\Library\DataPermission\Attribute\DataScope;
use App\Library\DataPermission\Context as DataPermissionContext;
use Hyperf\Context\Context;
use Hyperf\Database\Query\Builder;
use Hyperf\Di\Annotation\Aspect;
Expand All @@ -12,37 +23,36 @@
#[Aspect]
final class DataScopeAspect extends AbstractAspect
{

public const CONTEXT_KEY = 'data_permission';

public array $annotations = [
DataScope::class
DataScope::class,
];

public array $classes = [
Builder::class.'::update',
Builder::class.'::delete',
Builder::class.'::runSelect',
Builder::class . '::update',
Builder::class . '::delete',
Builder::class . '::runSelect',
];

public function process(ProceedingJoinPoint $proceedingJoinPoint)
{
if (
isset($proceedingJoinPoint->getAnnotationMetadata()->class[DataScope::class]) ||
isset($proceedingJoinPoint->getAnnotationMetadata()->method[DataScope::class])
){
isset($proceedingJoinPoint->getAnnotationMetadata()->class[DataScope::class])
|| isset($proceedingJoinPoint->getAnnotationMetadata()->method[DataScope::class])
) {
return $this->handleDataScope($proceedingJoinPoint);
}

if ($proceedingJoinPoint->className === Builder::class){
if ($proceedingJoinPoint->methodName==='runSelect'){
if ($proceedingJoinPoint->className === Builder::class) {
if ($proceedingJoinPoint->methodName === 'runSelect') {
return $this->handleSelect($proceedingJoinPoint);
}
if ($proceedingJoinPoint->methodName==='delete'){
if ($proceedingJoinPoint->methodName === 'delete') {
return $this->handleDelete($proceedingJoinPoint);
}
if ($proceedingJoinPoint->methodName==='update'){
return $this->handleUpdate($proceedingJoinPoint);
if ($proceedingJoinPoint->methodName === 'update') {
return $this->handleUpdate($proceedingJoinPoint);
}
}
return $proceedingJoinPoint->process();
Expand All @@ -64,18 +74,27 @@ protected function handleSelect(ProceedingJoinPoint $proceedingJoinPoint)
* @var Builder $builder
*/
$builder = $proceedingJoinPoint->getInstance();
if (Context::has(self::CONTEXT_KEY)){
if (Context::has(self::CONTEXT_KEY)) {
// todo 做数据权限处理
}
return $proceedingJoinPoint->process();
}


protected function handleDataScope(ProceedingJoinPoint $proceedingJoinPoint)
{
Context::set(self::CONTEXT_KEY, 1);
$result = $proceedingJoinPoint->process();
/**
* @var DataScope $attribute
*/
$attribute = $proceedingJoinPoint->getAnnotationMetadata()->class[DataScope::class];
if ($attribute === null) {

Check failure on line 90 in app/Library/DataPermission/Aspects/DataScopeAspect.php

View workflow job for this annotation

GitHub Actions / Test on PHP8.1 Swow-develop

Strict comparison using === between App\Library\DataPermission\Attribute\DataScope and null will always evaluate to false.

Check failure on line 90 in app/Library/DataPermission/Aspects/DataScopeAspect.php

View workflow job for this annotation

GitHub Actions / Test on PHP8.2 Swow-develop

Strict comparison using === between App\Library\DataPermission\Attribute\DataScope and null will always evaluate to false.

Check failure on line 90 in app/Library/DataPermission/Aspects/DataScopeAspect.php

View workflow job for this annotation

GitHub Actions / Test on PHP8.1 Swoole-v5.0.3

Strict comparison using === between App\Library\DataPermission\Attribute\DataScope and null will always evaluate to false.

Check failure on line 90 in app/Library/DataPermission/Aspects/DataScopeAspect.php

View workflow job for this annotation

GitHub Actions / Test on PHP8.2 Swoole-v5.0.3

Strict comparison using === between App\Library\DataPermission\Attribute\DataScope and null will always evaluate to false.

Check failure on line 90 in app/Library/DataPermission/Aspects/DataScopeAspect.php

View workflow job for this annotation

GitHub Actions / Test on PHP8.3 Swoole-master

Strict comparison using === between App\Library\DataPermission\Attribute\DataScope and null will always evaluate to false.

Check failure on line 90 in app/Library/DataPermission/Aspects/DataScopeAspect.php

View workflow job for this annotation

GitHub Actions / Test on PHP8.1 Swoole-master

Strict comparison using === between App\Library\DataPermission\Attribute\DataScope and null will always evaluate to false.

Check failure on line 90 in app/Library/DataPermission/Aspects/DataScopeAspect.php

View workflow job for this annotation

GitHub Actions / Test on PHP8.3 Swoole-v5.1.5

Strict comparison using === between App\Library\DataPermission\Attribute\DataScope and null will always evaluate to false.

Check failure on line 90 in app/Library/DataPermission/Aspects/DataScopeAspect.php

View workflow job for this annotation

GitHub Actions / Test on PHP8.2 Swoole-master

Strict comparison using === between App\Library\DataPermission\Attribute\DataScope and null will always evaluate to false.

Check failure on line 90 in app/Library/DataPermission/Aspects/DataScopeAspect.php

View workflow job for this annotation

GitHub Actions / Test on PHP8.1 Swoole-v5.1.5

Strict comparison using === between App\Library\DataPermission\Attribute\DataScope and null will always evaluate to false.

Check failure on line 90 in app/Library/DataPermission/Aspects/DataScopeAspect.php

View workflow job for this annotation

GitHub Actions / Test on PHP8.3 Swow-develop

Strict comparison using === between App\Library\DataPermission\Attribute\DataScope and null will always evaluate to false.

Check failure on line 90 in app/Library/DataPermission/Aspects/DataScopeAspect.php

View workflow job for this annotation

GitHub Actions / Test on PHP8.2 Swoole-v5.1.5

Strict comparison using === between App\Library\DataPermission\Attribute\DataScope and null will always evaluate to false.

Check failure on line 90 in app/Library/DataPermission/Aspects/DataScopeAspect.php

View workflow job for this annotation

GitHub Actions / build Code coverage report (ubuntu-latest, 8.1, v5.1.3)

Strict comparison using === between App\Library\DataPermission\Attribute\DataScope and null will always evaluate to false.
$attribute = $proceedingJoinPoint->getAnnotationMetadata()->method[DataScope::class];
}
DataPermissionContext::setDeptColumn($attribute->getDeptColumn());
DataPermissionContext::setCreatedByColumn($attribute->getCreatedByColumn());
DataPermissionContext::setScopeType($attribute->getScopeType());
$result = $proceedingJoinPoint->process();
Context::destroy(self::CONTEXT_KEY);
return $result;
}
}
}
35 changes: 32 additions & 3 deletions app/Library/DataPermission/Attribute/DataScope.php
Original file line number Diff line number Diff line change
@@ -1,12 +1,41 @@
<?php

declare(strict_types=1);
/**
* This file is part of MineAdmin.
*
* @link https://www.mineadmin.com
* @document https://doc.mineadmin.com
* @contact [email protected]
* @license https://github.com/mineadmin/MineAdmin/blob/master/LICENSE
*/

namespace App\Library\DataPermission\Attribute;

use Attribute;
use App\Library\DataPermission\ScopeType;
use Hyperf\Di\Annotation\AbstractAnnotation;

#[Attribute(Attribute::TARGET_CLASS|Attribute::TARGET_METHOD)]
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD)]
final class DataScope extends AbstractAnnotation
{
public function __construct(
private readonly string $deptColumn = 'dept_id',
private readonly string $createdByColumn = 'created_by',
private readonly ScopeType $scopeType = ScopeType::DEPT_CREATED_BY,
) {}

public function getDeptColumn(): string
{
return $this->deptColumn;
}

public function getCreatedByColumn(): string
{
return $this->createdByColumn;
}

}
public function getScopeType(): ScopeType
{
return $this->scopeType;
}
}
54 changes: 54 additions & 0 deletions app/Library/DataPermission/Context.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

declare(strict_types=1);
/**
* This file is part of MineAdmin.
*
* @link https://www.mineadmin.com
* @document https://doc.mineadmin.com
* @contact [email protected]
* @license https://github.com/mineadmin/MineAdmin/blob/master/LICENSE
*/

namespace App\Library\DataPermission;

use Hyperf\Context\Context as Ctx;

final class Context
{
private const DEPT_COLUMN_KEY = 'data_permission_dept_column';

private const CREATED_BY_COLUMN_KEY = 'data_permission_created_by_column';

private const SCOPE_TYPE_KEY = 'data_permission_scope_type';

public static function getDeptColumn(): string
{
return Ctx::get(self::DEPT_COLUMN_KEY, 'dept_id');
}

public static function setDeptColumn(string $column = 'dept_id'): void
{
Ctx::set(self::DEPT_COLUMN_KEY, $column);
}

public static function getCreatedByColumn(): string
{
return Ctx::get(self::CREATED_BY_COLUMN_KEY, 'created_by');
}

public static function setCreatedByColumn(string $column = 'created_by'): void
{
Ctx::set(self::CREATED_BY_COLUMN_KEY, $column);
}

public static function setScopeType(ScopeType $scopeType): void
{
Ctx::set(self::SCOPE_TYPE_KEY, $scopeType);
}

public static function getScopeType(): ScopeType
{
return Ctx::get(self::SCOPE_TYPE_KEY, ScopeType::DEPT_CREATED_BY);
}
}
82 changes: 82 additions & 0 deletions app/Library/DataPermission/Factory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<?php

declare(strict_types=1);
/**
* This file is part of MineAdmin.
*
* @link https://www.mineadmin.com
* @document https://doc.mineadmin.com
* @contact [email protected]
* @license https://github.com/mineadmin/MineAdmin/blob/master/LICENSE
*/

namespace App\Library\DataPermission;

use App\Library\DataPermission\Rule\Rule;
use App\Model\DataPermission\Policy;
use App\Model\Permission\User;
use Hyperf\Database\Query\Builder;

final class Factory
{
public function __construct(
private readonly Rule $rule
) {}

public function build(
Builder $builder,
User $user,
): void {
if ($user->isSuperAdmin()) {
return;
}
if (($policy = $user->getPolicy()) === null) {
return;
}
$scopeType = Context::getScopeType();
switch ($scopeType) {
case ScopeType::CREATED_BY:
self::handleCreatedBy($user, $policy, $builder);
break;
case ScopeType::DEPT:
self::handleDept($user, $policy, $builder);
break;
case ScopeType::DEPT_CREATED_BY:
self::handleDeptCreatedBy($user, $policy, $builder);
break;
case ScopeType::DEPT_OR_CREATED_BY:
self::handleDeptOrCreatedBy($user, $policy, $builder);
break;
}
}

private function handleCreatedBy(User $user, Policy $policy, Builder $builder): void
{
$createdByList = $this->rule->getCreatedByList($user, $policy);
$builder->whereIn(Context::getCreatedByColumn(), $createdByList);
}

private function handleDept(User $user, Policy $policy, Builder $builder): void
{
$deptList = $this->rule->getDeptIds($user, $policy);
$builder->whereIn(Context::getDeptColumn(), $deptList);
}

private function handleDeptCreatedBy(User $user, Policy $policy, Builder $builder): void
{
$createdByList = $this->rule->getCreatedByList($user, $policy);
$deptList = $this->rule->getDeptIds($user, $policy);
$builder->whereIn(Context::getCreatedByColumn(), $createdByList)
->whereIn(Context::getDeptColumn(), $deptList);
}

private function handleDeptOrCreatedBy(User $user, Policy $policy, Builder $builder): void
{
$createdByList = $this->rule->getCreatedByList($user, $policy);
$deptList = $this->rule->getDeptIds($user, $policy);
$builder->where(static function (Builder $query) use ($createdByList, $deptList) {
$query->whereIn(Context::getCreatedByColumn(), $createdByList)
->orWhereIn(Context::getDeptColumn(), $deptList);
});
}
}
15 changes: 11 additions & 4 deletions app/Library/DataPermission/Manager.php
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
<?php

namespace App\Library\DataPermission;
declare(strict_types=1);
/**
* This file is part of MineAdmin.
*
* @link https://www.mineadmin.com
* @document https://doc.mineadmin.com
* @contact [email protected]
* @license https://github.com/mineadmin/MineAdmin/blob/master/LICENSE
*/

final class Manager
{
namespace App\Library\DataPermission;

}
final class Manager {}
34 changes: 34 additions & 0 deletions app/Library/DataPermission/Rule/CustomFuncFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

declare(strict_types=1);
/**
* This file is part of MineAdmin.
*
* @link https://www.mineadmin.com
* @document https://doc.mineadmin.com
* @contact [email protected]
* @license https://github.com/mineadmin/MineAdmin/blob/master/LICENSE
*/

namespace App\Library\DataPermission\Rule;

final class CustomFuncFactory
{
/**
* @var array<string,\Closure>
*/
private static array $customFunc = [];

public static function registerCustomFunc(string $name, \Closure $func): void
{
self::$customFunc[$name] = $func;
}

public static function getCustomFunc(string $name): \Closure
{
if (isset(self::$customFunc[$name])) {
return self::$customFunc[$name];
}
throw new \RuntimeException('Custom func not found');
}
}
Loading

0 comments on commit aea2d49

Please sign in to comment.