Anyon e634118a22 refactor(plugin): 迁移 v8 插件化组件体系
将 v6 中直接放在本地 app 的后台与微信能力迁移为 v8 插件组件,并把运行时基础能力沉淀到独立插件包。

主要内容:

- 新增 think-library、system、worker、static、install 等基础插件包。

- 新增 account、payment、wechat-client、wechat-service、wemall、wuma 等业务插件包。

- 移除 v6 的 app/admin 与 app/wechat 本地应用实现,改由插件分发接管。

- 将 Helper 能力彻底并入 System,统一为 plugin\system\helper\* 命名空间。

- 同步插件迁移发布清单与根 route 占位,保证安装发布流程可复现。
2026-05-08 15:30:46 +08:00

116 lines
4.6 KiB
PHP

<?php
declare(strict_types=1);
/**
* +----------------------------------------------------------------------
* | ThinkAdmin Plugin for ThinkAdminDeveloper
* +----------------------------------------------------------------------
* | Copyright (c) 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | Official Website: https://thinkadmin.top
* +----------------------------------------------------------------------
* | Licensed: https://mit-license.org
* | Disclaimer: https://thinkadmin.top/disclaimer
* | Vip Rights: https://thinkadmin.top/vip-introduce
* +----------------------------------------------------------------------
* | Gitee Repository: https://gitee.com/zoujingli/ThinkAdmin
* | Github Repository: https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace plugin\system\tests;
use plugin\system\middleware\RbacAccess;
use plugin\system\service\AuthService;
use think\admin\runtime\RequestContext;
use think\admin\service\AuthResponse;
use think\admin\tests\Support\SqliteIntegrationTestCase;
use think\exception\HttpResponseException;
use think\Request;
use think\Response;
/**
* @internal
* @coversNothing
*/
class RbacAccessTest extends SqliteIntegrationTestCase
{
protected function defineSchema(): void {}
public function testHandleReturnsUnauthorizedResponseWhenAuthMissing(): void
{
AuthService::registerCheckCallable(static fn ($current, $methods, $userNodes): bool => false);
$response = $this->callMiddleware();
$payload = json_decode($response->getContent(), true) ?: [];
$this->assertSame(200, $response->getCode());
$this->assertSame(AuthResponse::STATUS_UNAUTHORIZED, intval($payload['code'] ?? 0));
$this->assertSame(AuthResponse::ERROR_UNAUTHORIZED, $payload['error'] ?? '');
$this->assertSame('请重新登录!', $payload['info'] ?? '');
$this->assertNotEmpty($payload['url'] ?? '');
}
public function testHandleReturnsForbiddenResponseWhenLoginHasNoPermission(): void
{
RequestContext::instance()->setAuth([
'id' => 1,
'username' => 'tester',
'nodes' => [],
], 'system-token', true);
AuthService::registerCheckCallable(static fn ($current, $methods, $userNodes): bool => false);
$response = $this->callMiddleware();
$payload = json_decode($response->getContent(), true) ?: [];
$this->assertSame(200, $response->getCode());
$this->assertSame(AuthResponse::STATUS_FORBIDDEN, intval($payload['code'] ?? 0));
$this->assertSame(AuthResponse::ERROR_FORBIDDEN, $payload['error'] ?? '');
$this->assertSame('禁用访问!', $payload['info'] ?? '');
$this->assertArrayNotHasKey('url', $payload);
}
public function testHandleUsesRecordedAuthFailureStatus(): void
{
AuthService::registerCheckCallable(static fn ($current, $methods, $userNodes): bool => false);
$response = $this->callMiddleware(function (): void {
RequestContext::instance()->clearAuth(true);
RequestContext::instance()->setAuthFailure(
AuthResponse::STATUS_FORBIDDEN,
'账号已经被禁用,请联系管理员!',
AuthResponse::ERROR_FORBIDDEN
);
});
$payload = json_decode($response->getContent(), true) ?: [];
$this->assertSame(200, $response->getCode());
$this->assertSame(AuthResponse::STATUS_FORBIDDEN, intval($payload['code'] ?? 0));
$this->assertSame(AuthResponse::ERROR_FORBIDDEN, $payload['error'] ?? '');
$this->assertSame('账号已经被禁用,请联系管理员!', $payload['info'] ?? '');
$this->assertArrayNotHasKey('url', $payload);
}
private function callMiddleware(?callable $beforeHandle = null): Response
{
$request = (new Request())
->setController('index')
->setAction('index');
$this->activateApplicationContext($request);
$this->app->config->set([
'rbac_ignore' => [],
'rbac_login' => 'system/login/index',
], 'app');
sysvar('think.admin.methods', []);
is_callable($beforeHandle) && $beforeHandle();
$middleware = new RbacAccess($this->app);
try {
return $middleware->handle($request, static fn (Request $current): Response => Response::create($current->pathinfo() ?: 'ok'));
} catch (HttpResponseException $exception) {
return $exception->getResponse();
}
}
}