""" SMS 服务抽象层 Mock 模式:验证码打印到后端日志 后续可接入阿里云短信 / 腾讯云 SMS,只需替换 Provider 实现 """ import logging from abc import ABC, abstractmethod from app.core.config import settings logger = logging.getLogger(__name__) class SmsProvider(ABC): """SMS 发送提供者基类""" @abstractmethod async def send(self, phone: str, code: str) -> bool: """发送验证码短信,成功返回 True""" ... class MockSmsProvider(SmsProvider): """Mock 提供者 —— 验证码打印到后端日志(开发/测试环境用)""" async def send(self, phone: str, code: str) -> bool: logger.info("=" * 50) logger.info("📱 [MockSMS] 验证码: %s → %s", code, phone) logger.info("=" * 50) return True class TencentSmsProvider(SmsProvider): """腾讯云 SMS 提供者(待接入)""" def __init__(self, secret_id: str, secret_key: str, app_id: str, sign_name: str, template_id: str): self.secret_id = secret_id self.secret_key = secret_key self.app_id = app_id self.sign_name = sign_name self.template_id = template_id async def send(self, phone: str, code: str) -> bool: # TODO: 接入腾讯云 SMS SDK logger.warning("TencentSmsProvider 尚未实现,验证码: %s → %s", code, phone) return False class AliyunSmsProvider(SmsProvider): """阿里云短信提供者(待接入)""" def __init__(self, access_key_id: str, access_key_secret: str, sign_name: str, template_code: str): self.access_key_id = access_key_id self.access_key_secret = access_key_secret self.sign_name = sign_name self.template_code = template_code async def send(self, phone: str, code: str) -> bool: # TODO: 接入阿里云短信 SDK logger.warning("AliyunSmsProvider 尚未实现,验证码: %s → %s", code, phone) return False def get_sms_provider() -> SmsProvider: """根据配置返回 SMS 提供者实例""" provider_name = getattr(settings, "SMS_PROVIDER", "mock") or "mock" if provider_name == "tencent": return TencentSmsProvider( secret_id=getattr(settings, "TENCENT_SMS_SECRET_ID", ""), secret_key=getattr(settings, "TENCENT_SMS_SECRET_KEY", ""), app_id=getattr(settings, "TENCENT_SMS_APP_ID", ""), sign_name=getattr(settings, "TENCENT_SMS_SIGN_NAME", ""), template_id=getattr(settings, "TENCENT_SMS_TEMPLATE_ID", ""), ) elif provider_name == "aliyun": return AliyunSmsProvider( access_key_id=getattr(settings, "ALIYUN_SMS_ACCESS_KEY_ID", ""), access_key_secret=getattr(settings, "ALIYUN_SMS_ACCESS_KEY_SECRET", ""), sign_name=getattr(settings, "ALIYUN_SMS_SIGN_NAME", ""), template_code=getattr(settings, "ALIYUN_SMS_TEMPLATE_CODE", ""), ) else: return MockSmsProvider()