将 Clover 从上层产品包旧仓库中独立出来,建立专属版本控制。 当前状态=纵切片端到端已打通(登录→选品→出文出图→审核→下载包), M1文案质量去套路化已验收。此提交作为后续按核销清单逐条修复的基线。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
44 lines
1.3 KiB
Python
44 lines
1.3 KiB
Python
"""
|
||
app/core/sse_ticket.py — SSE 一次性短票 (ticket) 签发与验证
|
||
倩倩姐2026-06-08拍板:SSE 认证不传 JWT,改传 ticket。
|
||
ticket 存 Redis,TTL 60s,验一次即删,换不了其他接口。
|
||
"""
|
||
import secrets
|
||
from typing import Optional
|
||
|
||
TICKET_TTL_SECONDS = 60
|
||
TICKET_KEY_PREFIX = "sse_ticket:"
|
||
|
||
|
||
def _redis_key(ticket: str) -> str:
|
||
return f"{TICKET_KEY_PREFIX}{ticket}"
|
||
|
||
|
||
def issue_ticket(redis_client, task_id: int, workspace_id: int) -> str:
|
||
"""
|
||
签发一次性 SSE ticket,写入 Redis,TTL 60s。
|
||
返回 ticket 字符串(32字节 hex,共64字符)。
|
||
"""
|
||
ticket = secrets.token_hex(32)
|
||
value = f"{task_id}:{workspace_id}"
|
||
redis_client.setex(_redis_key(ticket), TICKET_TTL_SECONDS, value)
|
||
return ticket
|
||
|
||
|
||
def consume_ticket(redis_client, ticket: str) -> Optional[tuple[int, int]]:
|
||
"""
|
||
验证并消费 ticket(用后即删,一次性)。
|
||
成功返回 (task_id, workspace_id),失败返回 None。
|
||
"""
|
||
if not ticket:
|
||
return None
|
||
key = _redis_key(ticket)
|
||
value = redis_client.getdel(key) # 原子取出并删除
|
||
if not value:
|
||
return None
|
||
try:
|
||
task_id_str, ws_str = value.split(":", 1)
|
||
return int(task_id_str), int(ws_str)
|
||
except (ValueError, AttributeError):
|
||
return None
|