Files
chunyu_project/utils/response_codes.py
T
root 3618323192 fix(security): P1/P2 审计修复 + JWT HttpOnly Cookie 双模认证 + 限流
- P0/P1 审计修复: 滑块验证码不再下发 x_position/成败即销毁 key、
  user-login 补失败计数+滑块门控、限流标识改 X-Real-IP、
  百度翻译 appkey 环境化、ChangeEmail/ChangePhone 补调 avalidate、
  logs/tasks.py Count(filter=Q) 修复、chat 收藏 SSRF 内网黑名单
- P1 #6/7: token_blacklist + ROTATE_REFRESH_TOKENS 开启,
  /user/token/refresh/ 挂载
- #2 JWT HttpOnly Cookie 双模认证: user/cookie_auth.py 种/清 Cookie,
  user/authentication.py CookieOrHeaderJWTAuthentication(Bearer 优先/_COOKIE 兜底),
  user/views/token.py CookieTokenRefreshView + UserLogoutAPIView(/user/logout/),
  create_standardized_response 自动对含 token 的响应种 Cookie,
  异步视图内 RefreshToken.for_user 全部 sync_to_async 包裹(修 SynchronousOnlyOperation 500),
  WS ChatConsumer 优先读 Cookie token
- P2 #11 限流: utils/rate_limit.py 固定窗口频控,
  shorturl 生成 匿名10次/分+登录60次/分, 邮箱验证码 同邮箱60s1次+同IP10次/10min,
  登录/注册验证码 错5次作废+成功即销毁防重放, 换绑邮箱/手机 同步落地,
  urls.py 补挂 shorturl 路由(此前 404)
2026-09-08 11:28:00 +08:00

132 lines
4.7 KiB
Python

"""
Response codes and messages enumeration for standardized API responses
This module contains all response codes and messages used across the application.
Codes are 5-digit numbers:
- 10000-19999: Success codes
- 20000-29999: Error codes
"""
from enum import IntEnum, Enum
class ResponseCode(IntEnum):
"""Response codes enumeration (5-digit numbers)"""
SUCCESS = 10000
EMAIL_SENT_REGISTER = 10001
EMAIL_SENT_LOGIN = 10002
REGISTRATION_SUCCESS = 10003
LOGIN_SUCCESS = 10004
PASSWORD_CHANGED = 10005
PASSWORD_SET = 10006
EMAIL_CHANGE_CODE_SENT = 10007
EMAIL_CHANGED = 10008
PARAMETER_ERROR = 20001
EMAIL_EMPTY = 20002
EMAIL_SEND_FAILED = 20003
VERIFICATION_CODE_EXPIRED = 20004
USER_DATA_INVALID = 20005
VERIFICATION_CODE_ERROR = 20006
LOGIN_VERIFICATION_EXPIRED = 20007
LOGIN_VERIFICATION_ERROR = 20008
SERVER_INTERNAL_ERROR = 20009
OLD_PASSWORD_ERROR = 20010
PASSWORD_MISMATCH = 20011
PASSWORD_TOO_SHORT = 20012
PASSWORD_TOO_WEAK = 20013
EMAIL_SAME_AS_OLD = 20014
EMAIL_ALREADY_IN_USE = 20015
RESET_CODE_SENT = 10009
PASSWORD_RESET_SUCCESS = 10010
VALIDATION_ERROR = 20016
NOT_FOUND = 20017
USER_NOT_FOUND = 20018
CAPTCHA_ERROR = 20020
CAPTCHA_EXPIRED = 20021
CAPTCHA_REQUIRED = 20022
EMAIL_DOMAIN_INVALID = 20023
class ResponseMessage:
"""Response messages enumeration (static class)"""
SUCCESS = 'Success'
EMAIL_SENT_REGISTER = '账号未注册,已发送注册邮件'
EMAIL_SENT_LOGIN = '邮件发送成功'
REGISTRATION_SUCCESS = '注册成功'
LOGIN_SUCCESS = '登录成功'
PASSWORD_CHANGED = '密码修改成功'
PASSWORD_SET = '密码设置成功'
EMAIL_CHANGE_CODE_SENT = '验证码已发送至邮箱'
EMAIL_CHANGED = '邮箱修改成功'
PARAMETER_ERROR = '参数异常'
EMAIL_EMPTY = '邮箱地址不能为空'
EMAIL_SEND_FAILED = '邮件发送失败'
VERIFICATION_CODE_EXPIRED = '验证码已过期或未发送'
USER_DATA_INVALID = '用户数据验证失败'
VERIFICATION_CODE_ERROR = '验证码错误'
LOGIN_VERIFICATION_EXPIRED = '验证码已过期或未发送'
LOGIN_VERIFICATION_ERROR = '验证码错误'
SERVER_INTERNAL_ERROR = '服务器内部错误'
OLD_PASSWORD_ERROR = '当前密码错误'
PASSWORD_MISMATCH = '两次输入的新密码不一致'
PASSWORD_TOO_SHORT = '密码长度不能少于8位'
PASSWORD_TOO_WEAK = '密码必须包含字母和数字'
EMAIL_SAME_AS_OLD = '新邮箱与当前邮箱相同'
EMAIL_ALREADY_IN_USE = '该邮箱已被其他账号使用'
RESET_CODE_SENT = '重置密码验证码已发送至邮箱'
PASSWORD_RESET_SUCCESS = '密码重置成功'
VALIDATION_ERROR = '数据验证失败'
NOT_FOUND = '资源不存在'
USER_NOT_FOUND = '该邮箱未注册'
CAPTCHA_ERROR = '验证码错误'
CAPTCHA_EXPIRED = '验证码已过期,请重新获取'
CAPTCHA_REQUIRED = '操作过于频繁,请输入验证码'
EMAIL_DOMAIN_INVALID = '邮箱域名不存在,请输入真实邮箱地址'
def get_response_message(code: ResponseCode) -> str:
"""Get the corresponding message for a response code."""
return getattr(ResponseMessage, code.name, str(code))
SUCCESS = 200
SERVER_INTERNAL_ERROR = 500
def create_standardized_response(data=None, code=None, status_code=200, message=None):
"""Create a standardized success response."""
from rest_framework.response import Response
response_data = {}
if data is not None:
response_data['data'] = data
if code is not None:
response_data['code'] = int(code)
response_data['message'] = message or get_response_message(code)
response = Response(response_data, status=status_code)
# 安全加固:若返回数据含 access 或 refresh,自动植入 HttpOnly Cookie 杜绝 XSS 窃取
if isinstance(data, dict):
access = data.get('access')
refresh = data.get('refresh')
if access or refresh:
try:
from user.cookie_auth import set_auth_cookies
set_auth_cookies(response, access_token=access, refresh_token=refresh)
except Exception:
pass
return response
def create_standardized_error_response(data=None, code=None, status_code=400, message=None):
"""Create a standardized error response."""
from rest_framework.response import Response
response_data = {}
if data is not None:
response_data['data'] = data
if code is not None:
response_data['code'] = int(code)
response_data['message'] = message or get_response_message(code)
else:
response_data['message'] = message or 'Unknown error'
return Response(response_data, status=status_code)