You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Django REST Framework项目中集成sms.to发送OTP?

在Django REST Framework中集成sms.to发送OTP的实现方案

因为目前没有官方或第三方维护的sms.to Python包,直接调用其REST API是最直接的方案,以下是具体步骤:

1. 准备工作

  • 登录sms.to后台获取你的API密钥,确保账户有足够余额或已完成身份验证
  • 在Django项目的settings.py中配置参数,建议用环境变量存储敏感信息:
    # settings.py
    import os
    SMSTO_API_KEY = os.environ.get('SMSTO_API_KEY')
    SMSTO_SENDER_ID = 'YourAppName'  # 替换为你在sms.to后台设置的发件人ID
    

2. 封装发送OTP的工具函数

创建utils/sms.py文件,封装API调用逻辑:

# utils/sms.py
import requests
from django.conf import settings

def send_otp(phone_number, otp_code):
    url = "https://api.sms.to/sms/send"
    headers = {
        "Authorization": f"Bearer {settings.SMSTO_API_KEY}",
        "Content-Type": "application/json"
    }
    payload = {
        "to": phone_number,  # 格式要求:带国家码,如+8613xxxxxxxxx
        "from": settings.SMSTO_SENDER_ID,
        "message": f"Your OTP code is {otp_code}. Valid for 5 minutes."
    }
    
    try:
        response = requests.post(url, json=payload, headers=headers)
        response.raise_for_status()
        return {"success": True, "data": response.json()}
    except requests.exceptions.RequestException as e:
        # 可根据需求添加日志记录
        return {"success": False, "error": str(e)}

3. 创建OTP存储模型

在对应app的models.py中添加OTP记录模型:

# models.py
from django.db import models
from django.utils import timezone
import uuid

class OTP(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    phone_number = models.CharField(max_length=20)
    otp_code = models.CharField(max_length=6)
    created_at = models.DateTimeField(auto_now_add=True)
    is_used = models.BooleanField(default=False)
    
    def is_expired(self):
        # 设置5分钟有效期,可按需调整
        return timezone.now() > self.created_at + timezone.timedelta(minutes=5)
    
    class Meta:
        indexes = [
            models.Index(fields=['phone_number', 'otp_code']),
        ]

执行迁移命令生效:

python manage.py makemigrations
python manage.py migrate

4. 实现DRF视图处理OTP发送与验证

发送OTP视图

# views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .models import OTP
from .utils.sms import send_otp
import random

class SendOTPView(APIView):
    def post(self, request):
        phone_number = request.data.get('phone_number')
        if not phone_number:
            return Response({"error": "Phone number is required"}, status=status.HTTP_400_BAD_REQUEST)
        
        # 生成6位随机OTP
        otp_code = str(random.randint(100000, 999999))
        
        # 调用发送函数
        sms_response = send_otp(phone_number, otp_code)
        if not sms_response['success']:
            return Response({"error": sms_response['error']}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
        
        # 清理旧OTP并保存新记录
        OTP.objects.filter(phone_number=phone_number).delete()
        OTP.objects.create(phone_number=phone_number, otp_code=otp_code)
        
        return Response({"message": "OTP sent successfully"}, status=status.HTTP_200_OK)

验证OTP视图

class VerifyOTPView(APIView):
    def post(self, request):
        phone_number = request.data.get('phone_number')
        otp_code = request.data.get('otp_code')
        
        if not phone_number or not otp_code:
            return Response({"error": "Phone number and OTP are required"}, status=status.HTTP_400_BAD_REQUEST)
        
        try:
            otp_record = OTP.objects.get(phone_number=phone_number, otp_code=otp_code, is_used=False)
        except OTP.DoesNotExist:
            return Response({"error": "Invalid OTP"}, status=status.HTTP_400_BAD_REQUEST)
        
        if otp_record.is_expired():
            return Response({"error": "OTP has expired"}, status=status.HTTP_400_BAD_REQUEST)
        
        # 标记OTP为已使用,防止重复验证
        otp_record.is_used = True
        otp_record.save()
        
        # 此处可添加后续业务逻辑,如生成登录Token、创建用户等
        return Response({"message": "OTP verified successfully"}, status=status.HTTP_200_OK)

5. 配置URL路由

在app的urls.py中添加路由映射:

# urls.py
from django.urls import path
from .views import SendOTPView, VerifyOTPView

urlpatterns = [
    path('send-otp/', SendOTPView.as_view(), name='send-otp'),
    path('verify-otp/', VerifyOTPView.as_view(), name='verify-otp'),
]

注意事项

  • 必须保证手机号带正确的国家码,否则sms.to API会拒绝请求
  • 生产环境建议对发送OTP的接口添加频率限制,防止恶意刷取
  • 可根据业务需求调整OTP的长度和有效期
  • 建议添加日志模块,记录短信发送的成功/失败状态,方便排查问题

内容的提问来源于stack exchange,提问作者mr_fahad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 03:10:24