security: harden proxy IP trust, token flow, health and sessions

This commit is contained in:
2026-02-09 09:14:47 +08:00
parent f645a0f8ea
commit ebfac7266b
7 changed files with 199 additions and 79 deletions

View File

@@ -1370,20 +1370,18 @@ def generate_email_token(email: str, token_type: str, user_id: int = None) -> st
return token
def verify_email_token(token: str, token_type: str) -> Optional[Dict[str, Any]]:
"""
验证Token
Returns:
成功返回 {'user_id': int, 'email': str},失败返回 None
"""
def _get_email_token_payload(token: str, token_type: str) -> Optional[Dict[str, Any]]:
"""获取并校验邮件Token不消费"""
with db_pool.get_db() as conn:
cursor = conn.cursor()
cursor.execute("""
cursor.execute(
"""
SELECT id, user_id, email, expires_at, used
FROM email_tokens
WHERE token = ? AND token_type = ?
""", (token, token_type))
""",
(token, token_type),
)
row = cursor.fetchone()
if not row:
@@ -1391,21 +1389,55 @@ def verify_email_token(token: str, token_type: str) -> Optional[Dict[str, Any]]:
token_id, user_id, email, expires_at, used = row
# 检查是否已使用
if used:
return None
# 检查是否过期
if parse_datetime(expires_at) < datetime.now(BEIJING_TZ):
return None
# 标记为已使用
cursor.execute("""
UPDATE email_tokens SET used = 1 WHERE id = ?
""", (token_id,))
conn.commit()
return {'token_id': token_id, 'user_id': user_id, 'email': email}
return {'user_id': user_id, 'email': email}
def consume_email_token(token_id: int) -> bool:
"""将邮件Token标记为已使用。"""
with db_pool.get_db() as conn:
cursor = conn.cursor()
cursor.execute(
"""
UPDATE email_tokens
SET used = 1
WHERE id = ? AND used = 0
""",
(int(token_id),),
)
conn.commit()
return cursor.rowcount > 0
def verify_email_token(token: str, token_type: str, *, consume: bool = True) -> Optional[Dict[str, Any]]:
"""
验证Token
Args:
token: token字符串
token_type: token类型
consume: 是否在验证成功后立刻消费默认True
Returns:
consume=True: {'user_id': int, 'email': str}
consume=False: {'token_id': int, 'user_id': int, 'email': str}
失败返回 None
"""
payload = _get_email_token_payload(token, token_type)
if not payload:
return None
if consume:
if not consume_email_token(payload['token_id']):
return None
return {'user_id': payload['user_id'], 'email': payload['email']}
return payload
def check_rate_limit(email: str, token_type: str) -> bool:
@@ -1600,29 +1632,7 @@ def verify_password_reset_token(token: str) -> Optional[Dict[str, Any]]:
Returns:
成功返回 {'user_id': int, 'email': str},失败返回 None
"""
with db_pool.get_db() as conn:
cursor = conn.cursor()
cursor.execute("""
SELECT id, user_id, email, expires_at, used
FROM email_tokens
WHERE token = ? AND token_type = ?
""", (token, EMAIL_TYPE_RESET))
row = cursor.fetchone()
if not row:
return None
token_id, user_id, email, expires_at, used = row
# 检查是否已使用
if used:
return None
# 检查是否过期
if parse_datetime(expires_at) < datetime.now(BEIJING_TZ):
return None
return {'user_id': user_id, 'email': email, 'token_id': token_id}
return verify_email_token(token, EMAIL_TYPE_RESET, consume=False)
def confirm_password_reset(token: str) -> Optional[Dict[str, Any]]:
@@ -1636,13 +1646,8 @@ def confirm_password_reset(token: str) -> Optional[Dict[str, Any]]:
if not result:
return None
# 标记为已使用
with db_pool.get_db() as conn:
cursor = conn.cursor()
cursor.execute("""
UPDATE email_tokens SET used = 1 WHERE id = ?
""", (result['token_id'],))
conn.commit()
if not consume_email_token(result['token_id']):
return None
return {'user_id': result['user_id'], 'email': result['email']}
@@ -1706,14 +1711,14 @@ def send_bind_email_verification(
)
def verify_bind_email_token(token: str) -> Optional[Dict[str, Any]]:
def verify_bind_email_token(token: str, *, consume: bool = True) -> Optional[Dict[str, Any]]:
"""
验证邮箱绑定Token
Returns:
成功返回 {'user_id': int, 'email': str},失败返回 None
"""
return verify_email_token(token, EMAIL_TYPE_BIND)
return verify_email_token(token, EMAIL_TYPE_BIND, consume=consume)
def send_security_alert_email(