# tests/api/test_auth.py import pytest def test_create_and_verify_token(): from sanguo_api.auth import create_token, verify_token, set_jwt_config set_jwt_config(secret="test_secret", expire_minutes=60) token = create_token("admin") assert isinstance(token, str) assert verify_token(token) == "admin" def test_verify_token_invalid_raises_401(): from fastapi import HTTPException from sanguo_api.auth import verify_token, set_jwt_config set_jwt_config(secret="test_secret", expire_minutes=60) with pytest.raises(HTTPException) as exc: verify_token("invalid.token.here") assert exc.value.status_code == 401 def test_hash_and_verify_password(): from sanguo_api.auth import hash_password, verify_password h = hash_password("mypass") assert h != "mypass" assert verify_password("mypass", h) is True assert verify_password("wrong", h) is False # ---- P1.4 token 静默刷新 ---- def test_token_expiry_helpers(): """get_token_exp 返回 unix 秒(供前端/拦截器判断剩余时间)。""" import time from sanguo_api.auth import create_token, get_token_exp, set_jwt_config set_jwt_config(secret="test_secret", expire_minutes=60) token = create_token("admin") exp = get_token_exp(token) assert exp is not None assert abs(exp - (time.time() + 3600)) < 30 # ≈ now + 60min def test_refresh_endpoint_returns_new_valid_token(): """POST /auth/refresh:有效旧 token → 新 token(可过 verify),返回 expires_in。""" from fastapi.testclient import TestClient from sanguo_api.app import create_app from sanguo_api.auth import hash_password, set_jwt_config, verify_token set_jwt_config(secret="test_secret", expire_minutes=60) app = create_app(db_path=":memory:", auth_config={ "username": "admin", "password_hash": hash_password("pass123"), "jwt_secret": "test_secret", "expire_minutes": 60, }) client = TestClient(app) old = client.post("/api/v1/auth/login", json={"username": "admin", "password": "pass123"}).json()["token"] r = client.post("/api/v1/auth/refresh", headers={"Authorization": f"Bearer {old}"}) assert r.status_code == 200 data = r.json() # 同秒签发的 JWT 可能逐字相同,以 exp 语义断言续期 from sanguo_api.auth import get_token_exp assert get_token_exp(data["token"]) >= get_token_exp(old) assert verify_token(data["token"]) == "admin" assert data["expires_in"] == 3600 def test_refresh_endpoint_rejects_expired_or_missing_token(): """过期/缺 token → 401(不放过期 token 无限续命)。""" import time import jwt as pyjwt from fastapi.testclient import TestClient from sanguo_api.app import create_app from sanguo_api.auth import hash_password, set_jwt_config set_jwt_config(secret="test_secret", expire_minutes=60) app = create_app(db_path=":memory:", auth_config={ "username": "admin", "password_hash": hash_password("pass123"), "jwt_secret": "test_secret", "expire_minutes": 60, }) client = TestClient(app) # 无 header assert client.post("/api/v1/auth/refresh").status_code == 401 # 过期 token(手工签一个已过期的) expired = pyjwt.encode( {"sub": "admin", "exp": int(time.time()) - 3600}, "test_secret", algorithm="HS256") r = client.post("/api/v1/auth/refresh", headers={"Authorization": f"Bearer {expired}"}) assert r.status_code == 401