feat(auth): AuthService 新增 getAuthPayload 权限载荷构建

This commit is contained in:
augushong
2026-10-04 00:47:11 +00:00
parent 1a27454c38
commit d3a44a2e1c
2 changed files with 171 additions and 0 deletions

View File

@@ -0,0 +1,132 @@
<?php
declare(strict_types=1);
namespace tests\Feature;
use app\common\constants\AdminConstant;
use app\common\service\AuthService;
use app\common\test\TestCase;
use think\facade\Db;
/**
* AuthService::getAuthPayload 权限载荷构建测试.
*
* 覆盖三组契约:
* a) 超管(AdminConstant::SUPER_ADMIN_ID)→ all === true
* b) 仅授权 system.quick/index 与 system.quick/read 的普通管理员
* → all === false,nodes['system.quick'] 恰为两者,不含 add/edit/delete
* c) 载荷格式:nodes 每个键不含 '/',每个值为非空字符串数组
*
* fixture 沿用 McpServiceTest 既定模式(ulthon-testing 技能约定):
* 事务内自造全新管理员/角色/节点授权,避开 SystemAuthNode 60 秒查询缓存与
* adminInfo autoCache 窗口;tearDown 自动回滚,无残留。
*/
class AuthPayloadTest extends TestCase
{
/** 受测控制器(system.quick 的 index/read 动作节点均经 CurdTrait 注解注册,auth 默认 true). */
private const CONTROLLER = 'system.quick';
/** 授权动作(恰为载荷期望值). */
private const ALLOWED_ACTIONS = ['index', 'read'];
/** 不应出现的动作(同控制器其余 auth 受控动作). */
private const FORBIDDEN_ACTIONS = ['add', 'edit', 'delete'];
/**
* fixture:角色(仅授权 index/read)+ 绑定该角色的启用管理员.
*
* @return int 管理员ID
*/
private function createRestrictedAdmin(): int
{
$roleId = Db::name('system_auth')->insertGetId([
'title' => 'apt' . uniqid(),
'status' => 2, // system_auth 枚举:1=禁用 2=启用
'sort' => 100,
'create_time' => time(),
'update_time' => time(),
'delete_time' => 0,
]);
foreach (self::ALLOWED_ACTIONS as $action) {
Db::name('system_auth_node')->insert([
'auth_id' => $roleId,
'node' => self::CONTROLLER . '/' . $action,
]);
}
return Db::name('system_admin')->insertGetId([
'username' => 'apt_' . uniqid(),
'password' => 'should-not-leak',
'auth_ids' => (string) $roleId,
'status' => 1,
'create_time' => time(),
'update_time' => time(),
'delete_time' => 0,
]);
}
// =========================================================================
// a) 超管
// =========================================================================
public function test_super_admin_payload_is_all_true(): void
{
$service = new AuthService(AdminConstant::SUPER_ADMIN_ID);
$payload = $service->getAuthPayload();
$this->assertTrue($payload['all']);
$this->assertSame([], $payload['nodes']);
}
// =========================================================================
// b) 普通管理员:按角色授权精确聚合
// =========================================================================
public function test_restricted_admin_payload_contains_only_seeded_nodes(): void
{
$adminId = $this->createRestrictedAdmin();
$service = new AuthService($adminId);
$payload = $service->getAuthPayload();
$this->assertFalse($payload['all']);
$this->assertArrayHasKey(self::CONTROLLER, $payload['nodes'], 'payload: ' . json_encode($payload, JSON_UNESCAPED_SLASHES));
$this->assertCount(
count(self::ALLOWED_ACTIONS),
$payload['nodes'][self::CONTROLLER],
'payload: ' . json_encode($payload, JSON_UNESCAPED_SLASHES)
);
$this->assertEqualsCanonicalizing(self::ALLOWED_ACTIONS, $payload['nodes'][self::CONTROLLER]);
foreach (self::FORBIDDEN_ACTIONS as $action) {
$this->assertNotContains($action, $payload['nodes'][self::CONTROLLER]);
}
}
// =========================================================================
// c) 载荷格式契约
// =========================================================================
public function test_payload_nodes_format_contract(): void
{
$adminId = $this->createRestrictedAdmin();
$service = new AuthService($adminId);
$payload = $service->getAuthPayload();
$this->assertFalse($payload['all']);
$this->assertIsArray($payload['nodes']);
$this->assertNotEmpty($payload['nodes'], '受限管理员 nodes 不应为空');
foreach ($payload['nodes'] as $controller => $actions) {
$this->assertIsString($controller);
$this->assertStringNotContainsString('/', $controller, '控制器键不得含 /');
$this->assertIsArray($actions);
$this->assertNotEmpty($actions);
foreach ($actions as $action) {
$this->assertIsString($action);
$this->assertNotSame('', $action, '动作不得为空字符串');
}
}
}
}