feat(cloud-console): add user authentication and administration

This commit is contained in:
2026-07-13 17:54:53 +08:00
parent 035b177128
commit cdef630e67
35 changed files with 4126 additions and 113 deletions
+84 -1
View File
@@ -139,6 +139,76 @@ class CloudClient:
resp = self._request("POST", "/plugins", json=payload)
return resp.json()
# --------------------------------------------------------------- user auth
def login(self, *, username: str, password: str) -> dict[str, Any]:
resp = self._request(
"POST",
"/auth/login",
json={"username": username, "password": password},
)
return resp.json()
def current_user(self) -> dict[str, Any]:
resp = self._request("GET", "/auth/me")
return resp.json()
def logout(self) -> None:
self._request("POST", "/auth/logout")
def change_password(self, *, current_password: str, new_password: str) -> None:
self._request(
"POST",
"/auth/password",
json={
"current_password": current_password,
"new_password": new_password,
},
)
def list_users(self, *, limit: int = 50, offset: int = 0) -> dict[str, Any]:
resp = self._request(
"GET",
"/users",
params={"limit": limit, "offset": offset},
)
return resp.json()
def create_user(
self,
*,
username: str,
display_name: str,
role: str,
password: str,
) -> dict[str, Any]:
resp = self._request(
"POST",
"/users",
json={
"username": username,
"display_name": display_name,
"role": role,
"password": password,
},
)
return resp.json()
def update_user(self, user_id: str, **changes: Any) -> dict[str, Any]:
resp = self._request("PATCH", f"/users/{user_id}", json=changes)
return resp.json()
def reset_user_password(self, user_id: str, *, password: str) -> dict[str, Any]:
resp = self._request(
"POST",
f"/users/{user_id}/password",
json={"password": password},
)
return resp.json()
def revoke_user_sessions(self, user_id: str) -> None:
self._request("DELETE", f"/users/{user_id}/sessions")
# ------------------------------------------------------------------ helpers
def _url(self, path: str) -> str:
@@ -152,12 +222,17 @@ class CloudClient:
json: dict[str, Any] | None = None,
params: dict[str, Any] | None = None,
) -> httpx.Response:
headers = dict(self._headers or {})
if method in {"POST", "PUT", "PATCH", "DELETE"} and not headers:
csrf_token = _cookie_value(self._http, "amcp_csrf")
if csrf_token:
headers["X-CSRF-Token"] = csrf_token
response = self._http.request(
method,
self._url(path),
json=json,
params=params,
headers=self._headers,
headers=headers or None,
auth=self._auth,
)
if response.is_success:
@@ -173,3 +248,11 @@ class CloudClient:
else CloudAPIError
)
raise error_type(response, str(detail))
def _cookie_value(client: Any, name: str) -> str | None:
cookies = getattr(client, "cookies", None)
if cookies is None:
return None
value = cookies.get(name)
return value if isinstance(value, str) else None