209 lines
6.1 KiB
Python
209 lines
6.1 KiB
Python
"""Phase 3 认证测试:注册、登录、登出、鉴权、IDOR 防护。"""
|
|
|
|
from fastapi.testclient import TestClient
|
|
|
|
from app.main import app
|
|
|
|
|
|
def _client() -> TestClient:
|
|
return TestClient(app, raise_server_exceptions=False)
|
|
|
|
|
|
# --- 注册 ---
|
|
|
|
def test_register_success() -> None:
|
|
with _client() as client:
|
|
resp = client.post("/api/auth/register", json={
|
|
"username": "alice",
|
|
"email": "alice@example.com",
|
|
"password": "password123",
|
|
})
|
|
assert resp.status_code == 201
|
|
body = resp.json()
|
|
assert body["username"] == "alice"
|
|
assert body["email"] == "alice@example.com"
|
|
assert body["storage_quota"] == 104_857_600
|
|
# Cookie 已签发
|
|
assert "session_id" in resp.cookies
|
|
|
|
|
|
def test_register_duplicate_username() -> None:
|
|
with _client() as client:
|
|
client.post("/api/auth/register", json={
|
|
"username": "bob",
|
|
"email": "bob@example.com",
|
|
"password": "password123",
|
|
})
|
|
resp = client.post("/api/auth/register", json={
|
|
"username": "bob",
|
|
"email": "bob2@example.com",
|
|
"password": "password123",
|
|
})
|
|
assert resp.status_code == 409
|
|
assert resp.json()["code"] == "USERNAME_TAKEN"
|
|
|
|
|
|
def test_register_duplicate_email() -> None:
|
|
with _client() as client:
|
|
client.post("/api/auth/register", json={
|
|
"username": "carol",
|
|
"email": "carol@example.com",
|
|
"password": "password123",
|
|
})
|
|
resp = client.post("/api/auth/register", json={
|
|
"username": "carol2",
|
|
"email": "carol@example.com",
|
|
"password": "password123",
|
|
})
|
|
assert resp.status_code == 409
|
|
assert resp.json()["code"] == "EMAIL_TAKEN"
|
|
|
|
|
|
def test_register_short_password() -> None:
|
|
with _client() as client:
|
|
resp = client.post("/api/auth/register", json={
|
|
"username": "dave",
|
|
"email": "dave@example.com",
|
|
"password": "short",
|
|
})
|
|
assert resp.status_code == 422
|
|
|
|
|
|
# --- 登录 ---
|
|
|
|
def test_login_by_username() -> None:
|
|
with _client() as client:
|
|
client.post("/api/auth/register", json={
|
|
"username": "eve",
|
|
"email": "eve@example.com",
|
|
"password": "password123",
|
|
})
|
|
resp = client.post("/api/auth/login", json={
|
|
"username_or_email": "eve",
|
|
"password": "password123",
|
|
})
|
|
assert resp.status_code == 200
|
|
assert resp.json()["username"] == "eve"
|
|
assert "session_id" in resp.cookies
|
|
|
|
|
|
def test_login_by_email() -> None:
|
|
with _client() as client:
|
|
client.post("/api/auth/register", json={
|
|
"username": "frank",
|
|
"email": "frank@example.com",
|
|
"password": "password123",
|
|
})
|
|
resp = client.post("/api/auth/login", json={
|
|
"username_or_email": "frank@example.com",
|
|
"password": "password123",
|
|
})
|
|
assert resp.status_code == 200
|
|
assert resp.json()["username"] == "frank"
|
|
|
|
|
|
def test_login_wrong_password() -> None:
|
|
with _client() as client:
|
|
client.post("/api/auth/register", json={
|
|
"username": "grace",
|
|
"email": "grace@example.com",
|
|
"password": "password123",
|
|
})
|
|
resp = client.post("/api/auth/login", json={
|
|
"username_or_email": "grace",
|
|
"password": "wrongpassword",
|
|
})
|
|
assert resp.status_code == 401
|
|
assert resp.json()["code"] == "AUTH_INVALID_CREDENTIALS"
|
|
|
|
|
|
def test_login_nonexistent_user() -> None:
|
|
with _client() as client:
|
|
resp = client.post("/api/auth/login", json={
|
|
"username_or_email": "nobody",
|
|
"password": "password123",
|
|
})
|
|
assert resp.status_code == 401
|
|
|
|
|
|
# --- 登出 ---
|
|
|
|
def test_logout() -> None:
|
|
with _client() as client:
|
|
client.post("/api/auth/register", json={
|
|
"username": "heidi",
|
|
"email": "heidi@example.com",
|
|
"password": "password123",
|
|
})
|
|
resp = client.post("/api/auth/logout")
|
|
assert resp.status_code == 204
|
|
|
|
|
|
# --- /api/me ---
|
|
|
|
def test_me_authenticated() -> None:
|
|
with _client() as client:
|
|
client.post("/api/auth/register", json={
|
|
"username": "ivan",
|
|
"email": "ivan@example.com",
|
|
"password": "password123",
|
|
})
|
|
resp = client.get("/api/auth/me")
|
|
assert resp.status_code == 200
|
|
body = resp.json()
|
|
assert body["username"] == "ivan"
|
|
assert body["storage_used"] == 0
|
|
|
|
|
|
def test_me_unauthenticated() -> None:
|
|
with _client() as client:
|
|
resp = client.get("/api/auth/me")
|
|
assert resp.status_code == 401
|
|
assert resp.json()["code"] == "AUTH_REQUIRED"
|
|
|
|
|
|
# --- IDOR 防护 ---
|
|
|
|
def test_user_a_cannot_see_user_b() -> None:
|
|
"""用户A 登录后,session 只能访问自己的 /me。"""
|
|
with _client() as client:
|
|
client.post("/api/auth/register", json={
|
|
"username": "user_a",
|
|
"email": "a@example.com",
|
|
"password": "password123",
|
|
})
|
|
# user_a 已登录(Cookie 自动携带)
|
|
me_resp = client.get("/api/auth/me")
|
|
assert me_resp.status_code == 200
|
|
assert me_resp.json()["username"] == "user_a"
|
|
|
|
|
|
def test_storage_endpoint() -> None:
|
|
with _client() as client:
|
|
client.post("/api/auth/register", json={
|
|
"username": "storage_user",
|
|
"email": "storage@example.com",
|
|
"password": "password123",
|
|
})
|
|
resp = client.get("/api/auth/storage")
|
|
assert resp.status_code == 200
|
|
body = resp.json()
|
|
assert body["storage_used"] == 0
|
|
assert body["storage_quota"] == 104_857_600
|
|
assert body["storage_quota_mb"] == 100.0
|
|
|
|
|
|
# --- free plan seed ---
|
|
|
|
def test_free_plan_auto_created() -> None:
|
|
"""free plan 应在应用启动时自动创建。"""
|
|
with _client() as client:
|
|
client.post("/api/auth/register", json={
|
|
"username": "plan_user",
|
|
"email": "plan@example.com",
|
|
"password": "password123",
|
|
})
|
|
resp = client.get("/api/auth/me")
|
|
assert resp.status_code == 200
|
|
assert resp.json()["storage_quota"] == 104_857_600
|