在准备环境前提交次全部更改。

This commit is contained in:
Neo
2026-02-19 08:35:13 +08:00
parent ded6dfb9d8
commit 4eac07da47
1387 changed files with 6107191 additions and 33002 deletions

View File

@@ -0,0 +1,147 @@
"""
JWT 认证模块单元测试。
覆盖:令牌生成、验证、过期、类型校验、密码哈希、依赖注入。
"""
import os
import time
import pytest
from jose import jwt as jose_jwt
# 测试前设置 JWT_SECRET_KEY避免空密钥
os.environ.setdefault("JWT_SECRET_KEY", "test-secret-key-for-unit-tests")
from app.auth.jwt import (
create_access_token,
create_refresh_token,
create_token_pair,
decode_access_token,
decode_refresh_token,
decode_token,
hash_password,
verify_password,
)
from app import config
# ---------------------------------------------------------------------------
# 密码哈希
# ---------------------------------------------------------------------------
class TestPasswordHashing:
def test_hash_and_verify(self):
raw = "my_secure_password"
hashed = hash_password(raw)
assert verify_password(raw, hashed)
def test_wrong_password_rejected(self):
hashed = hash_password("correct")
assert not verify_password("wrong", hashed)
def test_hash_is_not_plaintext(self):
raw = "plaintext123"
hashed = hash_password(raw)
assert hashed != raw
# ---------------------------------------------------------------------------
# 令牌生成与解码
# ---------------------------------------------------------------------------
class TestTokenCreation:
def test_access_token_contains_expected_fields(self):
token = create_access_token(user_id=1, site_id=100)
payload = decode_token(token)
assert payload["sub"] == "1"
assert payload["site_id"] == 100
assert payload["type"] == "access"
assert "exp" in payload
def test_refresh_token_contains_expected_fields(self):
token = create_refresh_token(user_id=2, site_id=200)
payload = decode_token(token)
assert payload["sub"] == "2"
assert payload["site_id"] == 200
assert payload["type"] == "refresh"
assert "exp" in payload
def test_token_pair_returns_both_tokens(self):
pair = create_token_pair(user_id=3, site_id=300)
assert "access_token" in pair
assert "refresh_token" in pair
assert pair["token_type"] == "bearer"
# 验证两个令牌类型不同
access_payload = decode_token(pair["access_token"])
refresh_payload = decode_token(pair["refresh_token"])
assert access_payload["type"] == "access"
assert refresh_payload["type"] == "refresh"
# ---------------------------------------------------------------------------
# 令牌类型校验
# ---------------------------------------------------------------------------
class TestTokenTypeValidation:
def test_decode_access_token_rejects_refresh(self):
"""access 解码器拒绝 refresh 令牌。"""
token = create_refresh_token(user_id=1, site_id=1)
with pytest.raises(Exception):
decode_access_token(token)
def test_decode_refresh_token_rejects_access(self):
"""refresh 解码器拒绝 access 令牌。"""
token = create_access_token(user_id=1, site_id=1)
with pytest.raises(Exception):
decode_refresh_token(token)
def test_decode_access_token_accepts_access(self):
token = create_access_token(user_id=5, site_id=50)
payload = decode_access_token(token)
assert payload["sub"] == "5"
assert payload["site_id"] == 50
def test_decode_refresh_token_accepts_refresh(self):
token = create_refresh_token(user_id=6, site_id=60)
payload = decode_refresh_token(token)
assert payload["sub"] == "6"
assert payload["site_id"] == 60
# ---------------------------------------------------------------------------
# 令牌过期
# ---------------------------------------------------------------------------
class TestTokenExpiry:
def test_expired_token_rejected(self):
"""手动构造已过期令牌,验证解码失败。"""
payload = {
"sub": "1",
"site_id": 1,
"type": "access",
"exp": int(time.time()) - 10, # 10 秒前过期
}
token = jose_jwt.encode(
payload, config.JWT_SECRET_KEY, algorithm=config.JWT_ALGORITHM
)
with pytest.raises(Exception):
decode_token(token)
# ---------------------------------------------------------------------------
# 无效令牌
# ---------------------------------------------------------------------------
class TestInvalidToken:
def test_garbage_token_rejected(self):
with pytest.raises(Exception):
decode_token("not.a.valid.jwt")
def test_wrong_secret_rejected(self):
"""用不同密钥签发的令牌应被拒绝。"""
payload = {"sub": "1", "site_id": 1, "type": "access", "exp": int(time.time()) + 3600}
token = jose_jwt.encode(payload, "wrong-secret", algorithm="HS256")
with pytest.raises(Exception):
decode_token(token)