"""A5.7 / ADR-0012:账号与登录态。 要证明三件事:密码不落盘、能力调用必须带登录态、登录态对不上就是拒绝。 """ from __future__ import annotations import json from pathlib import Path from fastapi.testclient import TestClient from aps.api.app import app from aps.identity import verify_password client = TestClient(app) ACCOUNTS_FILE = Path(__file__).resolve().parents[1] / "data" / "demo_accounts.json" DEMO_PASSWORD = "aps-demo-pass" def login(account_id: str = "E1001", password: str = DEMO_PASSWORD) -> dict: response = client.post("/api/auth/login", json={"accountId": account_id, "password": password}) return {"status": response.status_code, "body": response.json()} def auth_header(token: str) -> dict[str, str]: return {"authorization": f"Bearer {token}"} def test_password_is_never_stored_in_plaintext() -> None: """凭据文件里只有 PBKDF2 哈希;明文密码绝不落盘。""" raw = ACCOUNTS_FILE.read_text(encoding="utf-8") assert DEMO_PASSWORD not in raw, "演示密码不该出现在账号文件里" stored = json.loads(raw)["accounts"][0]["passwordHash"] assert stored.startswith("pbkdf2_sha256$"), stored assert verify_password(DEMO_PASSWORD, stored) assert not verify_password("wrong-password", stored) def test_login_returns_token_and_whoami_accepts_it() -> None: result = login() assert result["status"] == 200 body = result["body"] assert body["accountId"] == "E1001" assert body["token"].startswith("aps_") assert body["expiresAt"] > 0 who = client.get("/api/auth/whoami", headers=auth_header(body["token"])) assert who.status_code == 200 assert who.json()["displayName"] == body["displayName"] def test_wrong_password_is_rejected() -> None: result = login(password="not-the-password") assert result["status"] == 401 assert "token" not in result["body"] def test_whoami_rejects_unknown_token() -> None: assert client.get("/api/auth/whoami", headers=auth_header("aps_not-a-real-token")).status_code == 401 def test_capability_call_requires_login_state() -> None: """登录态归 APS 判:没带 token 的能力调用一律 401(D9)。""" response = client.post("/api/capabilities/aps.orders.query", json={"params": {}}) assert response.status_code == 401 assert "重新绑定" in response.json()["detail"] def test_capability_call_succeeds_with_token() -> None: token = login()["body"]["token"] response = client.post( "/api/capabilities/aps.orders.query", json={"params": {"limit": 2}}, headers=auth_header(token), ) assert response.status_code == 200 assert response.json()["status"] == "succeeded" def test_account_mismatch_is_forbidden() -> None: """平台传来的账号与登录态不是同一个人:拒绝,别拿别人的登录态干活。""" token = login()["body"]["token"] response = client.post( "/api/capabilities/aps.orders.query", json={"params": {}, "identity": {"accountId": "E1002"}}, headers=auth_header(token), ) assert response.status_code == 403 def test_logout_invalidates_token() -> None: token = login()["body"]["token"] assert client.post("/api/auth/logout", headers=auth_header(token)).json()["loggedOut"] is True assert client.get("/api/auth/whoami", headers=auth_header(token)).status_code == 401