Add Redis-based one-time download token support

Integrate Redis as a backend for one-time download token validation, with in-memory fallback. Added RedisManager for connection lifecycle, TokenStore for atomic token usage checks, and related configuration via environment variables. Updated download flow to ensure tokens are single-use, and improved API robustness for batch operations. Updated dependencies to include redis and cachetools.
This commit is contained in:
2025-12-26 18:47:46 +08:00
parent 3088a9d548
commit d8a229fccd
13 changed files with 302 additions and 15 deletions

View File

@@ -50,17 +50,20 @@ async def admin_required(
raise http_exceptions.raise_forbidden("Admin Required")
def verify_download_token(token: str) -> tuple[UUID, UUID] | None:
def verify_download_token(token: str) -> tuple[str, UUID, UUID] | None:
"""
验证下载令牌并返回 (file_id, owner_id)。
验证下载令牌并返回 (jti, file_id, owner_id)。
:param token: JWT 令牌字符串
:return: (file_id, owner_id) 或 None验证失败
:return: (jti, file_id, owner_id) 或 None验证失败
"""
try:
payload = jwt.decode(token, JWT.SECRET_KEY, algorithms=["HS256"])
if payload.get("type") != "download":
return None
return UUID(payload["file_id"]), UUID(payload["owner_id"])
jti = payload.get("jti")
if not jti:
return None
return jti, UUID(payload["file_id"]), UUID(payload["owner_id"])
except (jwt.ExpiredSignatureError, jwt.InvalidTokenError):
return None