瀏覽代碼

修复Handler机制:使用枚举权限范围,handle方法移至基类

核心修复:
- 权限范围必须使用SCOPE_TYPE枚举,不再使用字符串
- handle方法移至BaseHandler基类,实现模板方法模式
- 子类实现process方法处理具体业务逻辑

架构改进:
- HandlerInterface.getRequiredScopes()返回SCOPE_TYPE[]
- BaseHandler.handle()统一处理权限验证和异常
- BaseHandler.process()抽象方法由子类实现
- BaseHandler.validatePermissions()使用枚举值验证

修复的Handler:
- UserInfoHandler - 使用SCOPE_TYPE::USER_READ
- UserListHandler - 使用SCOPE_TYPE::USER_READ
- GameStatsHandler - 使用SCOPE_TYPE::GAME_READ
- FundBalanceHandler - 使用SCOPE_TYPE::FUND_READ

技术优势:
- 类型安全的权限验证
- 统一的请求处理流程
- 更好的代码复用和维护性
- 符合设计模式最佳实践
notfff 7 月之前
父節點
當前提交
7651c3b9f3

+ 2 - 1
app/Module/OpenAPI/Contracts/HandlerInterface.php

@@ -2,6 +2,7 @@
 
 namespace App\Module\OpenAPI\Contracts;
 
+use App\Module\OpenAPI\Enums\SCOPE_TYPE;
 use Illuminate\Http\JsonResponse;
 
 /**
@@ -32,7 +33,7 @@ interface HandlerInterface
     /**
      * 获取所需的权限范围
      *
-     * @return array
+     * @return SCOPE_TYPE[]
      */
     public function getRequiredScopes(): array;
 }

+ 41 - 3
app/Module/OpenAPI/Handlers/BaseHandler.php

@@ -4,6 +4,7 @@ namespace App\Module\OpenAPI\Handlers;
 
 use App\Module\OpenAPI\Contracts\HandlerInterface;
 use App\Module\OpenAPI\Services\ScopeService;
+use App\Module\OpenAPI\Enums\SCOPE_TYPE;
 use Illuminate\Http\JsonResponse;
 
 /**
@@ -20,6 +21,43 @@ abstract class BaseHandler implements HandlerInterface
         $this->scopeService = $scopeService;
     }
 
+    /**
+     * 处理请求(模板方法)
+     *
+     * @param array $data 请求数据
+     * @param array $context 上下文信息
+     * @return JsonResponse
+     */
+    public function handle(array $data, array $context = []): JsonResponse
+    {
+        try {
+            // 验证权限
+            $app = $this->getApp($context);
+            if (!$app) {
+                return $this->errorResponse('应用信息不存在', null, 404);
+            }
+
+            if (!$this->validatePermissions($app->scopes ?? [], $context)) {
+                return $this->errorResponse('权限不足', null, 403);
+            }
+
+            // 调用具体的业务处理方法
+            return $this->process($data, $context);
+
+        } catch (\Exception $e) {
+            return $this->errorResponse('请求处理失败', ['error' => $e->getMessage()], 500);
+        }
+    }
+
+    /**
+     * 具体的业务处理方法(由子类实现)
+     *
+     * @param array $data 请求数据
+     * @param array $context 上下文信息
+     * @return JsonResponse
+     */
+    abstract protected function process(array $data, array $context = []): JsonResponse;
+
     /**
      * 验证权限
      *
@@ -30,13 +68,13 @@ abstract class BaseHandler implements HandlerInterface
     public function validatePermissions(array $scopes, array $context = []): bool
     {
         $requiredScopes = $this->getRequiredScopes();
-        
+
         foreach ($requiredScopes as $requiredScope) {
-            if (!$this->scopeService->hasScope($scopes, $requiredScope)) {
+            if (!in_array($requiredScope->value, $scopes)) {
                 return false;
             }
         }
-        
+
         return true;
     }
 

+ 31 - 45
app/Module/OpenAPI/Handlers/Fund/FundBalanceHandler.php

@@ -4,6 +4,7 @@ namespace App\Module\OpenAPI\Handlers\Fund;
 
 use App\Module\OpenAPI\Handlers\BaseHandler;
 use App\Module\OpenAPI\Services\ScopeService;
+use App\Module\OpenAPI\Enums\SCOPE_TYPE;
 use Illuminate\Http\JsonResponse;
 
 /**
@@ -21,11 +22,11 @@ class FundBalanceHandler extends BaseHandler
     /**
      * 获取所需的权限范围
      *
-     * @return array
+     * @return SCOPE_TYPE[]
      */
     public function getRequiredScopes(): array
     {
-        return ['FUND_READ'];
+        return [SCOPE_TYPE::FUND_READ];
     }
 
     /**
@@ -35,55 +36,40 @@ class FundBalanceHandler extends BaseHandler
      * @param array $context 上下文信息
      * @return JsonResponse
      */
-    public function handle(array $data, array $context = []): JsonResponse
+    protected function process(array $data, array $context = []): JsonResponse
     {
-        try {
-            // 验证权限
-            $app = $this->getApp($context);
-            if (!$app) {
-                return $this->errorResponse('应用信息不存在', null, 404);
-            }
-
-            if (!$this->validatePermissions($app->scopes ?? [], $context)) {
-                return $this->errorResponse('权限不足', null, 403);
-            }
-
-            // 验证请求参数
-            $validationErrors = $this->validateData($data, [
-                'user_id' => 'required|integer|min:1',
-                'currency_types' => 'array',
-                'currency_types.*' => 'string|max:20',
-                'include_frozen' => 'boolean',
-            ]);
-
-            if ($validationErrors) {
-                return $this->errorResponse('参数验证失败', $validationErrors, 422);
-            }
-
-            // 获取参数
-            $userId = $data['user_id'];
-            $currencyTypes = $data['currency_types'] ?? [];
-            $includeFrozen = $data['include_frozen'] ?? false;
+        // 验证请求参数
+        $validationErrors = $this->validateData($data, [
+            'user_id' => 'required|integer|min:1',
+            'currency_types' => 'array',
+            'currency_types.*' => 'string|max:20',
+            'include_frozen' => 'boolean',
+        ]);
+
+        if ($validationErrors) {
+            return $this->errorResponse('参数验证失败', $validationErrors, 422);
+        }
 
-            // 调用Fund模块服务获取余额信息
-            $balanceInfo = $this->getFundBalance($userId, $currencyTypes, $includeFrozen);
+        // 获取参数
+        $userId = $data['user_id'];
+        $currencyTypes = $data['currency_types'] ?? [];
+        $includeFrozen = $data['include_frozen'] ?? false;
 
-            if (!$balanceInfo) {
-                return $this->errorResponse('用户不存在或无资金账户', null, 404);
-            }
+        // 调用Fund模块服务获取余额信息
+        $balanceInfo = $this->getFundBalance($userId, $currencyTypes, $includeFrozen);
 
-            // 记录操作日志
-            $this->logAction('fund.balance.get', [
-                'user_id' => $userId,
-                'currency_types' => $currencyTypes,
-                'include_frozen' => $includeFrozen,
-            ], $context);
+        if (!$balanceInfo) {
+            return $this->errorResponse('用户不存在或无资金账户', null, 404);
+        }
 
-            return $this->successResponse('获取资金余额成功', $balanceInfo);
+        // 记录操作日志
+        $this->logAction('fund.balance.get', [
+            'user_id' => $userId,
+            'currency_types' => $currencyTypes,
+            'include_frozen' => $includeFrozen,
+        ], $context);
 
-        } catch (\Exception $e) {
-            return $this->errorResponse('获取资金余额失败', ['error' => $e->getMessage()], 500);
-        }
+        return $this->successResponse('获取资金余额成功', $balanceInfo);
     }
 
     /**

+ 30 - 44
app/Module/OpenAPI/Handlers/Game/GameStatsHandler.php

@@ -4,6 +4,7 @@ namespace App\Module\OpenAPI\Handlers\Game;
 
 use App\Module\OpenAPI\Handlers\BaseHandler;
 use App\Module\OpenAPI\Services\ScopeService;
+use App\Module\OpenAPI\Enums\SCOPE_TYPE;
 use Illuminate\Http\JsonResponse;
 
 /**
@@ -21,11 +22,11 @@ class GameStatsHandler extends BaseHandler
     /**
      * 获取所需的权限范围
      *
-     * @return array
+     * @return SCOPE_TYPE[]
      */
     public function getRequiredScopes(): array
     {
-        return ['GAME_READ'];
+        return [SCOPE_TYPE::GAME_READ];
     }
 
     /**
@@ -35,53 +36,38 @@ class GameStatsHandler extends BaseHandler
      * @param array $context 上下文信息
      * @return JsonResponse
      */
-    public function handle(array $data, array $context = []): JsonResponse
+    protected function process(array $data, array $context = []): JsonResponse
     {
-        try {
-            // 验证权限
-            $app = $this->getApp($context);
-            if (!$app) {
-                return $this->errorResponse('应用信息不存在', null, 404);
-            }
-
-            if (!$this->validatePermissions($app->scopes ?? [], $context)) {
-                return $this->errorResponse('权限不足', null, 403);
-            }
-
-            // 验证请求参数
-            $validationErrors = $this->validateData($data, [
-                'date_from' => 'date',
-                'date_to' => 'date|after_or_equal:date_from',
-                'user_id' => 'integer|min:1',
-                'game_type' => 'string|max:50',
-            ]);
-
-            if ($validationErrors) {
-                return $this->errorResponse('参数验证失败', $validationErrors, 422);
-            }
-
-            // 获取统计参数
-            $dateFrom = $data['date_from'] ?? now()->subDays(7)->toDateString();
-            $dateTo = $data['date_to'] ?? now()->toDateString();
-            $userId = $data['user_id'] ?? null;
-            $gameType = $data['game_type'] ?? '';
+        // 验证请求参数
+        $validationErrors = $this->validateData($data, [
+            'date_from' => 'date',
+            'date_to' => 'date|after_or_equal:date_from',
+            'user_id' => 'integer|min:1',
+            'game_type' => 'string|max:50',
+        ]);
+
+        if ($validationErrors) {
+            return $this->errorResponse('参数验证失败', $validationErrors, 422);
+        }
 
-            // 调用Game模块服务获取统计数据
-            $stats = $this->getGameStats($dateFrom, $dateTo, $userId, $gameType);
+        // 获取统计参数
+        $dateFrom = $data['date_from'] ?? now()->subDays(7)->toDateString();
+        $dateTo = $data['date_to'] ?? now()->toDateString();
+        $userId = $data['user_id'] ?? null;
+        $gameType = $data['game_type'] ?? '';
 
-            // 记录操作日志
-            $this->logAction('game.stats.get', [
-                'date_from' => $dateFrom,
-                'date_to' => $dateTo,
-                'user_id' => $userId,
-                'game_type' => $gameType,
-            ], $context);
+        // 调用Game模块服务获取统计数据
+        $stats = $this->getGameStats($dateFrom, $dateTo, $userId, $gameType);
 
-            return $this->successResponse('获取游戏统计成功', $stats);
+        // 记录操作日志
+        $this->logAction('game.stats.get', [
+            'date_from' => $dateFrom,
+            'date_to' => $dateTo,
+            'user_id' => $userId,
+            'game_type' => $gameType,
+        ], $context);
 
-        } catch (\Exception $e) {
-            return $this->errorResponse('获取游戏统计失败', ['error' => $e->getMessage()], 500);
-        }
+        return $this->successResponse('获取游戏统计成功', $stats);
     }
 
     /**

+ 17 - 31
app/Module/OpenAPI/Handlers/User/UserInfoHandler.php

@@ -4,6 +4,7 @@ namespace App\Module\OpenAPI\Handlers\User;
 
 use App\Module\OpenAPI\Handlers\BaseHandler;
 use App\Module\OpenAPI\Services\ScopeService;
+use App\Module\OpenAPI\Enums\SCOPE_TYPE;
 use Illuminate\Http\JsonResponse;
 
 /**
@@ -21,11 +22,11 @@ class UserInfoHandler extends BaseHandler
     /**
      * 获取所需的权限范围
      *
-     * @return array
+     * @return SCOPE_TYPE[]
      */
     public function getRequiredScopes(): array
     {
-        return ['USER_READ'];
+        return [SCOPE_TYPE::USER_READ];
     }
 
     /**
@@ -35,41 +36,26 @@ class UserInfoHandler extends BaseHandler
      * @param array $context 上下文信息
      * @return JsonResponse
      */
-    public function handle(array $data, array $context = []): JsonResponse
+    protected function process(array $data, array $context = []): JsonResponse
     {
-        try {
-            // 验证权限
-            $app = $this->getApp($context);
-            if (!$app) {
-                return $this->errorResponse('应用信息不存在', null, 404);
-            }
+        // 获取用户ID
+        $userId = $data['user_id'] ?? $this->getUserId($context);
 
-            if (!$this->validatePermissions($app->scopes ?? [], $context)) {
-                return $this->errorResponse('权限不足', null, 403);
-            }
-
-            // 获取用户ID
-            $userId = $data['user_id'] ?? $this->getUserId($context);
-            
-            if (!$userId) {
-                return $this->errorResponse('用户ID不能为空', null, 400);
-            }
+        if (!$userId) {
+            return $this->errorResponse('用户ID不能为空', null, 400);
+        }
 
-            // 调用User模块服务获取用户信息
-            $userInfo = $this->getUserInfo($userId);
-            
-            if (!$userInfo) {
-                return $this->errorResponse('用户不存在', null, 404);
-            }
+        // 调用User模块服务获取用户信息
+        $userInfo = $this->getUserInfo($userId);
 
-            // 记录操作日志
-            $this->logAction('user.info.get', ['user_id' => $userId], $context);
+        if (!$userInfo) {
+            return $this->errorResponse('用户不存在', null, 404);
+        }
 
-            return $this->successResponse('获取用户信息成功', $userInfo);
+        // 记录操作日志
+        $this->logAction('user.info.get', ['user_id' => $userId], $context);
 
-        } catch (\Exception $e) {
-            return $this->errorResponse('获取用户信息失败', ['error' => $e->getMessage()], 500);
-        }
+        return $this->successResponse('获取用户信息成功', $userInfo);
     }
 
     /**

+ 29 - 43
app/Module/OpenAPI/Handlers/User/UserListHandler.php

@@ -4,6 +4,7 @@ namespace App\Module\OpenAPI\Handlers\User;
 
 use App\Module\OpenAPI\Handlers\BaseHandler;
 use App\Module\OpenAPI\Services\ScopeService;
+use App\Module\OpenAPI\Enums\SCOPE_TYPE;
 use Illuminate\Http\JsonResponse;
 
 /**
@@ -21,11 +22,11 @@ class UserListHandler extends BaseHandler
     /**
      * 获取所需的权限范围
      *
-     * @return array
+     * @return SCOPE_TYPE[]
      */
     public function getRequiredScopes(): array
     {
-        return ['USER_READ'];
+        return [SCOPE_TYPE::USER_READ];
     }
 
     /**
@@ -35,53 +36,38 @@ class UserListHandler extends BaseHandler
      * @param array $context 上下文信息
      * @return JsonResponse
      */
-    public function handle(array $data, array $context = []): JsonResponse
+    protected function process(array $data, array $context = []): JsonResponse
     {
-        try {
-            // 验证权限
-            $app = $this->getApp($context);
-            if (!$app) {
-                return $this->errorResponse('应用信息不存在', null, 404);
-            }
-
-            if (!$this->validatePermissions($app->scopes ?? [], $context)) {
-                return $this->errorResponse('权限不足', null, 403);
-            }
+        // 验证请求参数
+        $validationErrors = $this->validateData($data, [
+            'page' => 'integer|min:1',
+            'per_page' => 'integer|min:1|max:100',
+            'search' => 'string|max:100',
+            'status' => 'string|in:active,inactive,banned',
+        ]);
 
-            // 验证请求参数
-            $validationErrors = $this->validateData($data, [
-                'page' => 'integer|min:1',
-                'per_page' => 'integer|min:1|max:100',
-                'search' => 'string|max:100',
-                'status' => 'string|in:active,inactive,banned',
-            ]);
+        if ($validationErrors) {
+            return $this->errorResponse('参数验证失败', $validationErrors, 422);
+        }
 
-            if ($validationErrors) {
-                return $this->errorResponse('参数验证失败', $validationErrors, 422);
-            }
+        // 获取分页参数
+        $page = $data['page'] ?? 1;
+        $perPage = $data['per_page'] ?? 20;
+        $search = $data['search'] ?? '';
+        $status = $data['status'] ?? '';
 
-            // 获取分页参数
-            $page = $data['page'] ?? 1;
-            $perPage = $data['per_page'] ?? 20;
-            $search = $data['search'] ?? '';
-            $status = $data['status'] ?? '';
+        // 调用User模块服务获取用户列表
+        $userList = $this->getUserList($page, $perPage, $search, $status);
 
-            // 调用User模块服务获取用户列表
-            $userList = $this->getUserList($page, $perPage, $search, $status);
+        // 记录操作日志
+        $this->logAction('user.list.get', [
+            'page' => $page,
+            'per_page' => $perPage,
+            'search' => $search,
+            'status' => $status,
+        ], $context);
 
-            // 记录操作日志
-            $this->logAction('user.list.get', [
-                'page' => $page,
-                'per_page' => $perPage,
-                'search' => $search,
-                'status' => $status,
-            ], $context);
-
-            return $this->successResponse('获取用户列表成功', $userList);
-
-        } catch (\Exception $e) {
-            return $this->errorResponse('获取用户列表失败', ['error' => $e->getMessage()], 500);
-        }
+        return $this->successResponse('获取用户列表成功', $userList);
     }
 
     /**