阿里云短信服务(SMS)API 接入教程:支持 Vue + SpringBoot

cloud 2026-05-28 阅读 10
1

      无论是做用户注册、登录验证,还是订单状态通知,短信服务都是刚需。

很多新手看阿里云官方的短信文档,容易被一堆 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>

生产环境避坑指南(运维血泪经验)

  1. 小心接口被黑客“短信轰炸”!接口一上线,黑客就会用自动化脚本拿着几万个随机手机号来疯狂请求你的 /api/sms/send 接口。一晚上就能把你的阿里云账户余额全扣光。铁律防御:除了前端做 60 秒倒计时、后端用 Redis 限制单手机号 60 秒频率之外,针对发送短信的接口,必须强行加上“图形验证码”或“人机滑块验证”。只有拼图成功的合法请求,后端才发短信。
  2. 触发阿里云的“频次限制”报错阿里云短信官方自带了一套流控防刷机制(单手机号 1 分钟内不超过 1 条,1 小时内不超过 5 条,1 天内不超过 10 条)。如果你本地测试时疯狂给自己发短信,突然报错 isv.BUSINESS_LIMIT_CONTROL,别慌,不是代码写错了,是你被阿里云官方限流了,明天会自动解封。

这一套前后端闭环走下来,你的微服务应用就正式具备了合规、安全的短消息通知能力。赶快部署去试试看吧!


1
← 返回新闻中心