from rest_framework.throttling import SimpleRateThrottle class SmsPhoneMinuteThrottle(SimpleRateThrottle): """短信验证码:同一手机号 60 秒 1 次""" scope = 'sms_phone_minute' def get_cache_key(self, request, view): phone = request.data.get('phone') or request.query_params.get('phone') if not phone: return None return self.cache_format % {'scope': self.scope, 'ident': phone} class SmsPhoneDayThrottle(SimpleRateThrottle): """短信验证码:同一手机号 24 小时 ≤ 10 次""" scope = 'sms_phone_day' def get_cache_key(self, request, view): phone = request.data.get('phone') or request.query_params.get('phone') if not phone: return None return self.cache_format % {'scope': self.scope, 'ident': phone} class SmsIpThrottle(SimpleRateThrottle): """短信验证码:同一 IP 1 小时 ≤ 30 次""" scope = 'sms_ip' def get_cache_key(self, request, view): ident = self.get_ident(request) return self.cache_format % {'scope': self.scope, 'ident': ident} class RegisterIpThrottle(SimpleRateThrottle): """注册:同一 IP 1 小时 ≤ 10 次""" scope = 'register_ip' def get_cache_key(self, request, view): ident = self.get_ident(request) return self.cache_format % {'scope': self.scope, 'ident': ident} class ResetPhoneThrottle(SimpleRateThrottle): """找回密码:同手机号 1 小时 ≤ 5 次""" scope = 'reset_phone' def get_cache_key(self, request, view): phone = request.data.get('phone') or request.query_params.get('phone') if not phone: return None return self.cache_format % {'scope': self.scope, 'ident': phone} class PdfParseUserThrottle(SimpleRateThrottle): """PDF 解析:同用户 1 小时 ≤ 20 次""" scope = 'pdf_parse_user' def get_cache_key(self, request, view): if not request.user or not request.user.is_authenticated: return None return self.cache_format % {'scope': self.scope, 'ident': request.user.id} class ScoringRuleGenerateUserThrottle(SimpleRateThrottle): """AI 生成评分规则:同用户 1 小时 ≤ 20 次""" scope = 'scoring_rule_generate_user' def get_cache_key(self, request, view): if not request.user or not request.user.is_authenticated: return None return self.cache_format % {'scope': self.scope, 'ident': request.user.id}