feat(workbench): add runtime GIS and sample integrations
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
"""Reuse Next's product identity; no new user store or client-selected identity."""
|
||||
from dataclasses import dataclass
|
||||
from uuid import UUID
|
||||
|
||||
import httpx
|
||||
from fastapi import Request
|
||||
|
||||
from .errors import SampleFailure, ensure
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Identity:
|
||||
project_id: str
|
||||
user_id: str
|
||||
can_write: bool
|
||||
|
||||
|
||||
def next_get(request: Request, path: str, params=None):
|
||||
settings = request.app.state.settings
|
||||
try:
|
||||
with httpx.Client(base_url=settings.next_server_url, timeout=settings.timeout_seconds,
|
||||
follow_redirects=False, trust_env=False) as client:
|
||||
response = client.get(path, params=params, headers={
|
||||
"Authorization": request.headers.get("authorization", ""),
|
||||
"X-Project-Id": request.headers.get("x-project-id", ""),
|
||||
})
|
||||
if response.status_code in {401, 403, 404}:
|
||||
raise SampleFailure("SOURCE_ACCESS_DENIED", "Next 拒绝身份或来源对象访问", response.status_code)
|
||||
ensure(response.status_code == 200, "NEXT_UNAVAILABLE", "Next 服务不可用,未确认来源", 503)
|
||||
return response.json()
|
||||
except (httpx.HTTPError, ValueError) as exc:
|
||||
raise SampleFailure("NEXT_UNAVAILABLE", "无法核实 Next 身份或来源", 503) from exc
|
||||
|
||||
|
||||
def identity(request: Request) -> Identity:
|
||||
authorization = request.headers.get("authorization", "")
|
||||
project = request.headers.get("x-project-id", "")
|
||||
ensure(authorization.lower().startswith("bearer ") and bool(project),
|
||||
"AUTHENTICATION_REQUIRED", "需要 Bearer 和 X-Project-Id", 401)
|
||||
context = next_get(request, "/api/v1/agent-auth-context")
|
||||
try:
|
||||
user_id = str(UUID(context["user_id"]))
|
||||
project_id = str(UUID(context["project_id"]))
|
||||
ensure(project_id == str(UUID(project)), "PROJECT_MISMATCH", "项目身份不一致", 403)
|
||||
ensure(context["network"] == request.app.state.settings.project_code,
|
||||
"PROJECT_NOT_CONFIGURED", "该项目不是本外围样板的数据项目", 403)
|
||||
permissions = context["permissions"]
|
||||
ensure(isinstance(permissions, list) and "simulation.view" in permissions,
|
||||
"PERMISSION_DENIED", "没有样板读取权限", 403)
|
||||
can_write = "simulation.run" in permissions
|
||||
ensure(request.method == "GET" or can_write, "PERMISSION_DENIED", "没有样板修改权限", 403)
|
||||
except (KeyError, TypeError, ValueError) as exc:
|
||||
raise SampleFailure("INVALID_AUTH_CONTEXT", "Next 身份响应不完整", 502) from exc
|
||||
return Identity(project_id, user_id, can_write)
|
||||
Reference in New Issue
Block a user