| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167 |
- <?php
- namespace App\Module\OpenAPI\Middleware;
- use App\Module\OpenAPI\Enums\SCOPE_TYPE;
- use App\Module\OpenAPI\Models\OpenApiApp;
- use App\Module\OpenAPI\Services\OpenApiService;
- use Closure;
- use Illuminate\Http\Request;
- use Illuminate\Support\Facades\Log;
- /**
- * API权限范围中间件
- *
- * 用于验证应用是否具有访问特定API的权限
- */
- class ScopeMiddleware
- {
- protected OpenApiService $openApiService;
- public function __construct(OpenApiService $openApiService)
- {
- $this->openApiService = $openApiService;
- }
- /**
- * 处理请求
- *
- * @param Request $request
- * @param Closure $next
- * @param string $requiredScope 必需的权限范围
- * @return mixed
- */
- public function handle(Request $request, Closure $next, string $requiredScope)
- {
- // 获取应用信息
- $app = $this->getAppFromRequest($request);
-
- if (!$app) {
- return $this->forbiddenResponse('应用信息不存在');
- }
- // 检查权限范围
- if (!$this->checkScope($app, $requiredScope)) {
- return $this->forbiddenResponse("缺少必需的权限范围: {$requiredScope}");
- }
- // 记录权限检查日志
- $this->logScopeCheck($app, $requiredScope, $request);
- return $next($request);
- }
- /**
- * 从请求中获取应用信息
- *
- * @param Request $request
- * @return OpenApiApp|null
- */
- protected function getAppFromRequest(Request $request): ?OpenApiApp
- {
- // 从请求属性中获取应用信息(由认证中间件设置)
- return $request->attributes->get('openapi_app');
- }
- /**
- * 检查权限范围
- *
- * @param OpenApiApp $app
- * @param string $requiredScope
- * @return bool
- */
- protected function checkScope(OpenApiApp $app, string $requiredScope): bool
- {
- // 获取应用的权限范围
- $appScopes = $app->scopes ?? [];
-
- // 如果应用没有配置权限范围,拒绝访问
- if (empty($appScopes)) {
- return false;
- }
- // 检查是否有管理员权限(拥有所有权限)
- if (in_array('ADMIN', $appScopes)) {
- return true;
- }
- // 检查是否直接拥有所需权限
- if (in_array($requiredScope, $appScopes)) {
- return true;
- }
- // 检查权限依赖关系
- return $this->checkScopeDependencies($appScopes, $requiredScope);
- }
- /**
- * 检查权限依赖关系
- *
- * @param array $appScopes 应用拥有的权限
- * @param string $requiredScope 需要的权限
- * @return bool
- */
- protected function checkScopeDependencies(array $appScopes, string $requiredScope): bool
- {
- // 获取权限枚举实例
- $scopeEnum = SCOPE_TYPE::tryFrom($requiredScope);
-
- if (!$scopeEnum) {
- return false;
- }
- // 检查权限依赖
- $dependencies = $scopeEnum->getDependencies();
-
- foreach ($dependencies as $dependency) {
- if (in_array($dependency, $appScopes)) {
- return true;
- }
- }
- // 检查权限继承(如果有写权限,通常也有读权限)
- if (str_ends_with($requiredScope, '_READ')) {
- $writeScope = str_replace('_READ', '_WRITE', $requiredScope);
- if (in_array($writeScope, $appScopes)) {
- return true;
- }
- }
- return false;
- }
- /**
- * 记录权限检查日志
- *
- * @param OpenApiApp $app
- * @param string $requiredScope
- * @param Request $request
- * @return void
- */
- protected function logScopeCheck(OpenApiApp $app, string $requiredScope, Request $request): void
- {
- Log::info("Scope check passed", [
- 'app_id' => $app->app_id,
- 'required_scope' => $requiredScope,
- 'app_scopes' => $app->scopes,
- 'uri' => $request->getRequestUri(),
- 'method' => $request->getMethod(),
- 'ip' => $request->ip(),
- ]);
- }
- /**
- * 返回权限不足响应
- *
- * @param string $message
- * @return \Illuminate\Http\JsonResponse
- */
- protected function forbiddenResponse(string $message)
- {
- return response()->json([
- 'error' => 'insufficient_scope',
- 'message' => $message,
- 'required_scopes' => func_get_args()[1] ?? null,
- ], 403);
- }
- }
|