auth->guard('jwt')->user(); if (!$user) { return $this->forbiddenResponse('用户认证异常'); } // 获取用户 scope(含角色和 bitmap) $user_scope = $this->scopeTableManager->getUserScope($user->id); if (!$user_scope) { return $this->forbiddenResponse('用户权限未配置'); } $role = $user_scope['role']; $method = $request->getMethod(); // 通过 Dispatched 获取路由模板路径(如 /api/v1/users/{id}),解决参数化路由匹配问题 $dispatched = $request->getAttribute(Dispatched::class); $route_path = $dispatched?->handler?->route ?? $request->getUri()->getPath(); // ===== Step 1: 路由访问检查 ===== if ($role !== 'administrator') { $access_result = $this->checkRouteAccess($user->role_id, $method, $route_path); if ($access_result === false) { return $this->forbiddenResponse('无权访问该接口'); } } // ===== Step 2: 数据范围检查 ===== $scope_result = $this->applyDataScope($request, $role, $user_scope['scope'], $user); if ($scope_result instanceof ResponseInterface) { return $scope_result; } return $handler->handle($scope_result); } /** * 路由访问检查 * * @param int $role_id * @param string $method * @param string $path * @return bool */ protected function checkRouteAccess(int $role_id, string $method, string $path): bool { // 查找路由记录 $route = Route::query()->where('method', $method)->where('path', $path)->first(); if (!$route) { // 白名单模式:未注册到 routes 表的路由拒绝访问 return false; } // 1. 先查 override(优先级最高) $override = RoleRouteOverride::query() ->where('role_id', $role_id) ->where('route_id', $route->id) ->first(); if ($override) { return $override->allowed; } // 2. 查 route group 授权 if (!$route->group_id) { // 路由未分组且无 override → 拒绝 return false; } return Db::table('role_route_groups') ->where('role_id', $role_id) ->where('group_id', $route->group_id) ->exists(); } /** * 数据范围检查与注入 * * @return ServerRequestInterface|ResponseInterface */ protected function applyDataScope( ServerRequestInterface $request, string $role, string $bitmap, mixed $user, ): ServerRequestInterface|ResponseInterface { $params = $request->getQueryParams(); $company_id = isset($params['company_id']) ? (int) $params['company_id'] : null; $platform_id = isset($params['platform_id']) ? (int) $params['platform_id'] : null; $store_id = isset($params['store_id']) ? (int) $params['store_id'] : null; // --- administrator: 全部放行 --- if ($role === 'administrator') { $request = $request->withAttribute('scope_type', 'all'); $request = $request->withAttribute('scope_ids', []); return $request; } // --- developer: 基于维护的 platform --- if ($role === 'developer') { return $this->applyDeveloperScope($request, $user, $bitmap, $company_id, $platform_id, $store_id); } // --- accessor: 基于 bitmap store_ids --- return $this->applyAccessorScope($request, $bitmap, $company_id, $platform_id, $store_id); } /** * developer 角色的数据范围处理 * * @return ServerRequestInterface|ResponseInterface */ protected function applyDeveloperScope( ServerRequestInterface $request, mixed $user, string $bitmap, ?int $company_id, ?int $platform_id, ?int $store_id, ): ServerRequestInterface|ResponseInterface { $platform_ids = Platform::query()->where('developer_id', $user->id)->pluck('id')->toArray(); // 有 scope 参数时校验 if ($platform_id !== null && !in_array($platform_id, $platform_ids, true)) { return $this->forbiddenResponse('平台不在开发者权限范围内'); } if ($store_id !== null && !$this->bitmapService->has($bitmap, $store_id)) { return $this->forbiddenResponse('店铺不在开发者权限范围内'); } if ($company_id !== null) { $has_store = Store::query() ->where('company_id', $company_id) ->whereIn('platform_id', $platform_ids) ->exists(); if (!$has_store) { return $this->forbiddenResponse('公司不在开发者权限范围内'); } } // 注入 scope if ($platform_id === null && $store_id === null && $company_id === null) { $request = $request->withAttribute('scope_type', 'platform'); $request = $request->withAttribute('scope_ids', $platform_ids); } else { $request = $request->withAttribute('scope_type', 'store'); $request = $request->withAttribute('scope_ids', $this->bitmapService->decode($bitmap)); } return $request; } /** * accessor 角色的数据范围处理 * * @return ServerRequestInterface|ResponseInterface */ protected function applyAccessorScope( ServerRequestInterface $request, string $bitmap, ?int $company_id, ?int $platform_id, ?int $store_id, ): ServerRequestInterface|ResponseInterface { $allowed_store_ids = $this->bitmapService->decode($bitmap); // 有 scope 参数时校验 if ($store_id !== null && !$this->bitmapService->has($bitmap, $store_id)) { return $this->forbiddenResponse('店铺不在访问权限范围内'); } if ($company_id !== null) { $company_stores = Store::query()->where('company_id', $company_id)->pluck('id')->toArray(); if (empty(array_intersect($company_stores, $allowed_store_ids))) { return $this->forbiddenResponse('公司不在访问权限范围内'); } } if ($platform_id !== null) { $platform_stores = Store::query()->where('platform_id', $platform_id)->pluck('id')->toArray(); if (empty(array_intersect($platform_stores, $allowed_store_ids))) { return $this->forbiddenResponse('平台不在访问权限范围内'); } } // 注入已验证的 store_ids $request = $request->withAttribute('scope_type', 'store'); $request = $request->withAttribute('scope_ids', $allowed_store_ids); return $request; } /** * 返回 403 响应 */ protected function forbiddenResponse(string $message): ResponseInterface { return $this->response->json([ 'code' => 403, 'message' => $message, ])->withStatus(403); } }