""" 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