目录
短信接口(SMS API)的原理并不复杂,但它涉及到多个环节,包括:
-
第三方短信平台(如阿里云、腾讯云、Twilio)
-
HTTP 请求通信机制
-
验证签名、限流、模板审核等安全措施
🧩 一、短信接口的整体工作流程
假设你要开发一个“发送验证码”的功能,大致流程如下:
1. 向短信平台注册账号
你首先要在像阿里云短信服务、腾讯云短信、Twilio 等平台注册,申请接口权限。
2. 获取必要信息
你需要以下信息来调用 API:
-
API 访问地址(Endpoint)
-
Access Key(用于认证身份)
-
短信签名(Sender ID,如【你的应用名】)
-
短信模板(事先设定好的内容格式,比如“验证码为:${code},请在5分钟内输入。”)
3. 后端发起 HTTPS 请求
你的后端服务器调用平台提供的 API,一般是一个 POST 请求,内容包含:
{
"phone_number": "13812345678",
"template_id": "123456",
"template_param": {
"code": "648291"
},
"sign_name": "【应用名】",
"access_key": "你自己的Key"
}
4. 平台验证并发送
平台接收请求后,会验证请求合法性,包括:
-
签名是否正确
-
模板内容是否一致
-
请求是否超出频率限制
验证通过后,平台将短信发送到运营商(移动、联通、电信),再由运营商投递到用户手机。
🔐 二、安全机制设计(重点)
短信接口容易被滥用,所以平台通常加入以下防护机制:
机制 | 说明 |
---|---|
访问频率限制 | 每个 IP、每个手机号、每个账号 每分钟/每小时/每天最多发送几条短信。 |
模板审核 | 所有短信必须使用模板,平台审核通过后才可使用,防止发送恶意内容。 |
签名机制 | 请求中要加入签名参数(如 HMAC、SHA256),防止伪造请求。 |
验证码发送频控 | 典型规则是“每个手机号每60秒最多发送一次验证码”,避免短信轰炸。 |
图形验证码预验证 | 有时前端要先通过图形验证码验证,才能请求发送短信。 |
🛠️ 三、示例:调用短信 API(以腾讯云为例)
import requests
import json
from tencentcloud.sms.v20210111 import sms_client, models
# 用伪代码举例
url = "https://sms.tencentcloudapi.com"
headers = {
"Authorization": "你的签名",
"Content-Type": "application/json"
}
data = {
"PhoneNumberSet": ["+8613812345678"],
"SmsSdkAppId": "1400006666",
"SignName": "你的短信签名",
"TemplateId": "123456",
"TemplateParamSet": ["648291"]
}
response = requests.post(url, headers=headers, data=json.dumps(data))
print(response.json())
📦 四、常见短信平台推荐
名称 | 优点 | 网址 |
---|---|---|
腾讯云短信 | 中文文档好,国内投递成功率高 | https://cloud.tencent.com/product/sms |
阿里云短信 | 支持国际发送,服务成熟 | https://dysms.console.aliyun.com/ |
Twilio | 海外开发者首选,文档完善 | https://www.twilio.com/sms |
下面是一个完整的短信验证码发送系统后端示例,使用:
-
Flask:作为后端框架
-
Redis:存储验证码及冷却时间
-
腾讯云短信 API:用于发送短信验证码
✅ 功能说明
实现以下功能:
-
用户发送手机号,请求获取验证码;
-
验证冷却时间(60秒内不能重复发);
-
随机生成验证码(6位);
-
存入 Redis,有效期 5 分钟;
-
调用腾讯云短信 API 发送短信。
🛠️ 项目依赖(Python)
先安装依赖:
pip install flask redis tencentcloud-sdk-python sms
📦 项目结构(简化
sms_project/
├── app.py # Flask 主程序
├── tencent_sms.py # 腾讯云短信工具
└── config.py # 配置文件
🔑 config.py
# config.py
TENCENT_SMS_APP_ID = "1400XXXXXXX"
TENCENT_SMS_SECRET_ID = "你的SecretId"
TENCENT_SMS_SECRET_KEY = "你的SecretKey"
TENCENT_SMS_SIGN_NAME = "你的短信签名"
TENCENT_SMS_TEMPLATE_ID = "123456" # 验证码模板ID
REDIS_HOST = 'localhost'
REDIS_PORT = 6379
REDIS_DB = 0
💬 tencent_sms.py(封装腾讯云短信发送)
# tencent_sms.py
from tencentcloud.sms.v20210111 import sms_client, models
from tencentcloud.common import credential
from config import *
def send_sms(phone, code):
cred = credential.Credential(TENCENT_SMS_SECRET_ID, TENCENT_SMS_SECRET_KEY)
client = sms_client.SmsClient(cred, "ap-guangzhou")
req = models.SendSmsRequest()
req.SmsSdkAppId = TENCENT_SMS_APP_ID
req.SignName = TENCENT_SMS_SIGN_NAME
req.TemplateId = TENCENT_SMS_TEMPLATE_ID
req.TemplateParamSet = [code]
req.PhoneNumberSet = [f"+86{phone}"]
client.SendSms(req)
🚀 app.py(主程序)
# app.py
from flask import Flask, request, jsonify
import random
import redis
from tencent_sms import send_sms
from config import *
app = Flask(__name__)
r = redis.Redis(host=REDIS_HOST, port=REDIS_PORT, db=REDIS_DB)
@app.route('/send-code', methods=['POST'])
def send_code():
data = request.json
phone = data.get("phone")
if not phone:
return jsonify({"code": 400, "msg": "缺少手机号"}), 400
cooldown_key = f"sms_cooldown:{phone}"
code_key = f"sms_code:{phone}"
# 冷却时间检查(60秒)
if r.get(cooldown_key):
return jsonify({"code": 429, "msg": "请求太频繁,请稍后再试"}), 429
# 生成验证码
code = str(random.randint(100000, 999999))
# 存入 Redis
r.setex(code_key, 300, code) # 验证码有效期5分钟
r.setex(cooldown_key, 60, "1") # 冷却期60秒
try:
send_sms(phone, code)
return jsonify({"code": 200, "msg": "验证码发送成功"})
except Exception as e:
return jsonify({"code": 500, "msg": f"短信发送失败:{str(e)}"}), 500
if __name__ == '__main__':
app.run(debug=True)
📲 示例请求(用 Postman 或前端)
POST http://localhost:5000/send-code
Content-Type: application/json
{
"phone": "13812345678"
}
🧪 测试建议
-
腾讯云短信控制台里可以申请测试模板和测试号码,避免真实扣费;
-
Redis 可以用 Docker 快速启动
docker run -p 6379:6379 redis