feat(api): P1.4 web token 60min静默刷新—后端POST /auth/refresh(有效旧token换新,过期401不放行续命)+login/refresh返expires_in+get_token_exp;前端请求拦截器剩余<10min单飞预刷新(裸axios避递归/mock短路,失败静默降级走401兜底);治长回测轮询401跳登录;3新测试 [vps]
This commit is contained in:
@@ -22,3 +22,71 @@ def test_hash_and_verify_password():
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user