阿里云短信服务(SMS)API 接入教程:支持 Vue + SpringBoot
无论是做用户注册、登录验证,还是订单状态通知,短信服务都是刚需。
很多新手看阿里云官方的短信文档,容易被一堆 AccessKey、签名、模板、SDK 概念绕晕,再加上官方示例代码往往写得臃肿,一时间不知道怎么跟自己的前后端项目整合。
今天不扯废话,直接上实战。带你用最接地气的“真人写作风格”,5分钟跑通阿里云短信服务(SMS)从后台配置,到后端 Spring Boot 核心逻辑封装,再到前端 Vue 的完整倒计时实现。
核心交互流程
在写代码之前,先脑补一下验证码短信的闭环逻辑:
Plaintext
【Vue 前端】 ── 1. 输入手机号,点发送 ──> 【Spring Boot 后端】
▲ │
│ 2. 生成 6 位随机数
│ 3. 存入 Redis(设置5分钟过期)
│ 4. 调用阿里云 API 发送
│ │
│ ▼
【用户手机】 <─── 5. 收到短信验证码 ───── 【阿里云短信网关】
第一步:阿里云控制台开通与资质申请(2分钟)
由于国内防诈骗治理非常严格,短信服务必须先申请资质和签名,直接去调用 API 会报权限错误。
1. 开通服务
登录阿里云控制台,搜索 “短信服务”,点击开通(开通免费,发送按条扣费,建议顺手买个几十块钱的套餐包)。
2. 申请短信签名(你是谁)
- 进入短信服务控制台,左侧点击 “国内消息” $\rightarrow$ “签名管理” $\rightarrow$ “添加签名”。
- 签名名称:通常是你的网站名、APP名或公司简称(如 极客博客)。
- 签名来源:个人开发者一般选“已备案网站”或“真实应用”,需要提供你的 ICP 备案号 或应用截图。
3. 申请短信模板(你发的是什么)
- 切换到 “模板管理” $\rightarrow$ “添加模板”。
- 模板类型:选择 “验证码”。
- 模板名称:如 登录验证码。
- 模板内容:固定格式,变量用 ${code} 表示。例如:您正在登录系统,验证码为:${code},5分钟内有效,请勿泄露给他人。
- 提交审核,通常 10~30 分钟就能通过。记住通过后的 TemplateCode(如 SMS_1234567)。
第二步:后端 Spring Boot 核心对接(3分钟)
不要用老旧的旧版 SDK 了,我们直接采用阿里云最新的 V2.0 云原生 Java SDK,代码更精简。
1. 引入 Maven 依赖
在你的 Spring Boot 项目 pom.xml 中引入阿里云短信核心库:
XML
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>dysmsapi20170525</artifactId>
<version>3.0.0</version> </dependency>
2. 在 application.yml 中配置密钥
还记得我们上一期讲过的 RAM 最小权限原则吗?去阿里云 RAM 控制台建一个子账号,只赋予 AliyunDysmsFullAccess(短信管理)权限,生成一组 AK/SK 填在这里:
YAML
aliyun:
sms:
access-key-id: LTAI5tXXXXXXXXXXXX # 子账号AK
access-key-secret: Pn7yXXXXXXXXXXXXXXXX # 子账号SK
sign-name: 极客博客 # 你申请通过的签名
template-code: SMS_1234567 # 你申请通过的模板ID
3. 封装短信发送工具类
创建一个 Service,直接复制下面我为你精简优化后的纯干货代码:
Java
import com.aliyun.dysmsapi20170525.Client;
import com.aliyun.dysmsapi20170525.models.SendSmsRequest;
import com.aliyun.dysmsapi20170525.models.SendSmsResponse;
import com.aliyun.teaopenapi.models.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@Service
public class SmsService {
@Value("${aliyun.sms.access-key-id}")
private String accessKeyId;
@Value("${aliyun.sms.access-key-secret}")
private String accessKeySecret;
@Value("${aliyun.sms.sign-name}")
private String signName;
@Value("${aliyun.sms.template-code}")
private String templateCode;
/**
* 发送验证码短信
* @param phone 目标手机号
* @param code 随机验证码
*/
public boolean sendVerifyCode(String phone, String code) {
try {
// 1. 初始化配置客户端
Config config = new Config()
.setAccessKeyId(accessKeyId)
.setAccessKeySecret(accessKeySecret);
// 固定的短信服务接入点
config.endpoint = "dysmsapi.aliyuncs.com";
Client client = new Client(config);
// 2. 组装请求参数
SendSmsRequest request = new SendSmsRequest()
.setPhoneNumbers(phone)
.setSignName(signName)
.setTemplateCode(templateCode)
// 变量必须转成 JSON 字符串格式
.setTemplateParam("{\"code\":\"" + code + "\"}");
// 3. 执行发送
SendSmsResponse response = client.sendSms(request);
// 4. 判断发送结果
if ("OK".equals(response.getBody().getCode())) {
return true;
} else {
System.err.println("短信发送失败,原因: " + response.getBody().getMessage());
return false;
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}
4. 编写 Controller 业务接口
在 Controller 层,结合你的 Redis(这里用伪代码代替展示逻辑闭环):
Java
@RestController
@RequestMapping("/api/sms")
public class SmsController {
@Autowired
private SmsService smsService;
@Autowired
private StringRedisTemplate redisTemplate; // 注入Redis
@PostMapping("/send")
public ResponseEntity<String> sendCode(@RequestParam String phone) {
// 1. 简易手机号正则校验
if (!phone.matches("^1[3-9]\\d{9}$")) {
return ResponseEntity.badRequest().body("手机号格式不正确");
}
// 2. 防刷机制:检查 Redis 确定 60 秒内没有重复发送
if (Boolean.TRUE.equals(redisTemplate.hasKey("SMS_LIMIT:" + phone))) {
return ResponseEntity.status(HttpStatus.TOO_MANY_REQUESTS).body("发送太频繁,请稍后再试");
}
// 3. 生成 6 位随机数验证码
String code = String.valueOf((int)((Math.random() * 9 + 1) * 100000));
// 4. 调用阿里云服务发送
boolean isSuccess = smsService.sendVerifyCode(phone, code);
if (!isSuccess) {
return ResponseEntity.status(500).body("短信发送失败,请联系管理员");
}
// 5. 存入 Redis,设置 5 分钟有效期;同时设置一个 60 秒的防刷限制
redisTemplate.opsForValue().set("SMS_CODE:" + phone, code, 5, TimeUnit.MINUTES);
redisTemplate.opsForValue().set("SMS_LIMIT:" + phone, "1", 60, TimeUnit.SECONDS);
return ResponseEntity.ok("验证码发送成功");
}
}
第三步:前端 Vue 倒计时组件编写(1分钟)
后端搞定了,前端我们要防范用户狂点“发送”按钮,需要做一个标准的 60 秒倒计时。
这里以 Vue 3 (Composition API) + Axios 为例,直接上最直观的代码:
代码段
<template>
<div class="sms-box">
<input type="text" v-model="phone" placeholder="请输入手机号" />
<button :disabled="isCounting" @click="handleSend">
{{ isCounting ? `${countdown}秒后重新获取` : '获取验证码' }}
</button>
</div>
</template>
<script setup>
import { ref } from 'vue';
import axios from 'axios';
const phone = ref('');
const countdown = ref(60);
const isCounting = ref(false);
let timer = null;
const handleSend = async () => {
if (!/^1[3-9]\d{9}$/.test(phone.value)) {
alert('请输入正确的手机号');
return;
}
try {
// 调用后端接口
const res = await axios.post(`/api/sms/send?phone=${phone.value}`);
alert(res.data);
// 激活倒计时
startCountdown();
} catch (error) {
alert(error.response?.data || '请求失败');
}
};
const startCountdown = () => {
isCounting.value = true;
countdown.value = 60;
timer = setInterval(() => {
countdown.value--;
if (countdown.value <= 0) {
clearInterval(timer);
isCounting.value = false;
}
}, 1000);
};
</script>
生产环境避坑指南(运维血泪经验)
- 小心接口被黑客“短信轰炸”!接口一上线,黑客就会用自动化脚本拿着几万个随机手机号来疯狂请求你的 /api/sms/send 接口。一晚上就能把你的阿里云账户余额全扣光。铁律防御:除了前端做 60 秒倒计时、后端用 Redis 限制单手机号 60 秒频率之外,针对发送短信的接口,必须强行加上“图形验证码”或“人机滑块验证”。只有拼图成功的合法请求,后端才发短信。
- 触发阿里云的“频次限制”报错阿里云短信官方自带了一套流控防刷机制(单手机号 1 分钟内不超过 1 条,1 小时内不超过 5 条,1 天内不超过 10 条)。如果你本地测试时疯狂给自己发短信,突然报错 isv.BUSINESS_LIMIT_CONTROL,别慌,不是代码写错了,是你被阿里云官方限流了,明天会自动解封。
这一套前后端闭环走下来,你的微服务应用就正式具备了合规、安全的短消息通知能力。赶快部署去试试看吧!
