当前位置: 首页 > news >正文

从零用java实现 小红书 springboot vue uniapp(14) 集成阿里云短信验证码


从零用java实现 小红书 springboot vue uniapp(14) 集成阿里云短信验证码

移动端演示 http://8.146.211.120:8081/#/

管理端演示 http://8.146.211.120:8088/#/

项目整体介绍及演示

前言

在现代应用中,手机号不仅是用户的唯一标识,更是保障账户安全的第一道防线。通过短信验证码进行登录或注册,已成为行业标准。它省去了用户记忆复杂密码的麻烦,同时提供了可靠的身份验证。在本文中,我们将为我们的小红书项目集成阿里云短信服务,实现一个完整、安全、且对开发者友好的手机验证码登录流程。


在这里插入图片描述

核心技术实现

整个流程分为后端和前端两部分。后端负责生成验证码、调用阿里云接口发送短信、以及校验验证码的有效性。前端则负责提供用户界面,引导用户输入手机号并完成验证。

1. 后端实现:从配置到接口
步骤一:引入阿里云SDK依赖

首先,我们需要在项目的 pom.xml 中加入阿里云短信服务的Java SDK。

<dependency><groupId>com.aliyun</groupId><artifactId>dysmsapi20170525</artifactId><version>2.0.24</version> <!-- 请使用最新版本 -->
</dependency>
步骤二:参数化配置

为了代码的灵活性和安全性,我们将所有敏感信息和配置项都放入 application.yml 中。这样做的好处是,我们可以在不同环境(开发、测试、生产)中使用不同的配置,而无需修改代码。

# 阿里云短信服务
aliyun:sms:# 是否启用真实短信发送, false则为测试模式enabled: false # 阿里云账号的accessKeyIdaccess-key-id: YOUR_ACCESS_KEY_ID# 阿里云账号的accessKeySecretaccess-key-secret: YOUR_ACCESS_KEY_SECRET# 短信签名名称 (需在阿里云控制台申请)sign-name: 你的签名# 短信模板CODE (需在阿里云控制台申请)template-code: SMS_XXXXXX# 短信验证码有效期(分钟)expire-minutes: 1
  • enabled: 这是一个非常有用的开关。当设为 false 时,系统进入“测试模式”,验证码会直接在接口中返回,而不会真实发送,方便开发调试。
  • access-key-id & access-key-secret: 你的阿里云账户凭证。
  • sign-name & template-code: 在阿里云短信服务控制台创建的短信签名和模板。
步骤三:封装短信发送服务

接下来,我们创建一个 SmsServiceImpl,它将负责所有与发送短信相关的逻辑。这种封装能让我们的业务代码(如登录逻辑)保持干净,只需调用一个简单的方法即可。

SmsServiceImpl.java:

@Slf4j
@Service
public class SmsServiceImpl implements SmsService {@Autowiredprivate SmsProperties smsProperties;@Autowiredprivate AliyunSmsConfig aliyunSmsConfig;@Autowiredprivate SystemSettingService systemSettingService; // 用于获取系统设置@Overridepublic void sendMessage(String phoneNumber, String code) throws Exception {// 从系统设置或配置中获取当前的模式// String smsMode = systemSettingService.getSmsMode();// 此处我们直接使用yml中的配置boolean isRealMode = smsProperties.isEnabled();if (!isRealMode) {// 测试模式:只记录日志,不真实发送log.info("【测试模式】短信发送 - 手机号: {}, 验证码: {}", phoneNumber, code);return;}try {log.info("【真实模式】开始发送短信 - 手机号: {}, 验证码: {}", phoneNumber, code);Client client = aliyunSmsConfig.createClient();Map<String, String> templateParamMap = new HashMap<>();templateParamMap.put("code", code); // 模板参数,key必须与模板中的变量名一致String templateParam = JSON.toJSONString(templateParamMap);SendSmsRequest sendSmsRequest = new SendSmsRequest().setPhoneNumbers(phoneNumber).setSignName(smsProperties.getSignName()).setTemplateCode(smsProperties.getTemplateCode()).setTemplateParam(templateParam);RuntimeOptions runtime = new RuntimeOptions();SendSmsResponse sendSmsResponse = client.sendSmsWithOptions(sendSmsRequest, runtime);log.info("短信发送结果: {}", sendSmsResponse.getBody().getMessage());if (sendSmsResponse.getBody() == null || !"OK".equals(sendSmsResponse.getBody().getCode())) {throw new ApiException("短信发送失败: " + (sendSmsResponse.getBody() != null ? sendSmsResponse.getBody().getMessage() : "未知错误"));}} catch (Exception e) {log.error("短信发送异常", e);throw new ApiException("短信发送异常: " + e.getMessage());}}
}

该服务通过检查 aliyun.sms.enabled 的值来决定是打印日志(测试模式)还是调用阿里云API(真实模式)。

步骤四:创建登录接口

最后,我们在 LoginApi 中创建两个端点:一个用于获取验证码,另一个用于通过验证码登录。

LoginApi.java:

@RestController
public class LoginApi {@AutowiredLoginService loginService;@AutowiredAuthorService authorService;@Autowiredprivate JwtTokenUtil jwtTokenUtil;@ApiOperation(value = "获取验证码")@GetMapping("/api/getCode")public ResultBean<String> getCode(String phoneNumber) {// loginService 内部会生成验证码、存入Redis、并调用SmsService发送String code = loginService.sendSmsCode(phoneNumber);if (code == null) {// 真实模式下,service层返回null,提示用户return ResultBean.success("验证码已发送,请注意查收");}// 测试模式下,service层返回验证码,直接显示给前端return ResultBean.success(code);}@ApiOperation(value = "验证码登陆")@PostMapping("/api/checkCode")@Transactionalpublic ResultBean<Author> checkCode(@RequestBody PhoneLoginDto phoneLoginDto) {// 1. 校验验证码是否正确 (loginService会去Redis中比对)loginService.checkCode(phoneLoginDto);// 2. 验证通过,执行登录或注册逻辑Author author = authorService.selectAuthorByPhoneNumber(phoneLoginDto.getPhoneNumber());if(author == null){// 用户不存在,创建新用户author = authorService.createNewAuthor(phoneLoginDto.getPhoneNumber());} else if(author.getDeleted().equals(1)){throw new ApiException("当前用户状态异常~");}// 3. 生成Token并返回用户信息final String token = jwtTokenUtil.generateTokenByUserId(author.getAuthorId());author.setToken(token);return ResultBean.success(author);}
}
  • /api/getCode: 这个接口的设计完美地结合了测试与真实模式。在开发阶段,我们能立刻看到验证码,极大提高了调试效率。
  • /api/checkCode: 它首先验证验证码的正确性,然后执行“查找或创建”用户的逻辑,最后签发JWT令牌,完成整个登录闭环。
    主要逻辑是将验证码保存到redis 设置过期时间 到期重新发送 根据输入的值和redis数据库比较

2. 前端交互:Uniapp 实现

前端的实现相对直接,主要是在登录页面 login.vue 中完成。
在这里插入图片描述

  1. UI布局: 包含一个手机号输入框、一个“获取验证码”按钮和一个“登录”按钮。
  2. 获取验证码:
    • 点击“获取验证码”按钮时,调用后端的 /api/getCode 接口。
    • 接口调用成功后,启动一个60秒的倒计时,期间按钮变为不可点击状态,防止用户重复发送。
  3. 登录:
    • 用户输入手机号和收到的验证码后,点击“登录”按钮。
    • 调用后端的 /api/checkCode 接口,并传递手机号和验证码。
    • 登录成功后,后端会返回用户信息和Token。前端需要将这些信息(特别是Token)保存到本地存储(如 uni.setStorageSync),并跳转到应用主页。

通过前后端的紧密配合,我们就构建了一个完整且健壮的短信验证码登录功能。

代码地址
https://gitee.com/ddeatrr/springboot_vue_xhs

http://www.lryc.cn/news/598609.html

相关文章:

  • Android安全存储:加密文件与SharedPreferences最佳实践
  • 【C++】使用箱线图算法剔除数据样本中的异常值
  • 进程通信----匿名管道
  • 【redis其它面试问题】
  • PHP 与 Vue.js 结合的前后端分离架构
  • 工具分享02 | Python批量文件重命名工具
  • 电商接口什么意思?
  • 数据所有权与用益权分离:数字经济时代的权利博弈与“商业机遇”
  • Claude Code是如何做上下文工程的?
  • Maven Scope标签:解锁Java项目依赖管理的秘密武器
  • [嵌入式embed]ST官网-根据指定固件名下载固件库-STSWSTM32054[STM32F10x_StdPeriph_Lib_V3.5.0]
  • 使用maven-shade-plugin解决依赖版本冲突
  • RCLAMP0504S.TCT 升特半导体TVS二极管 无损传输+军工防护+纳米护甲 ESD防护芯片
  • 陕西地区特种作业操作证考试题库及答案(登高架设作业)
  • Product Hunt 每日热榜 | 2025-07-24
  • 2025年人形机器人动捕技术研讨会于7月31日在京召开
  • 火语言 RPA 在日常运维中的实践
  • ESP32使用 vscode IDF 创建项目到烧录运行全过程
  • 优选算法:移动零
  • 使用ffmpeg转码h265后mac默认播放器不支持问题
  • Mac电脑使用IDEA启动服务后,报service异常
  • 从零构建 Node20+pnpm+pm2 环境镜像:基于 Dockerfile 的两种方案及持久化配置指南
  • 开源Qwen凌晨暴击闭源Claude!刷新AI编程SOTA,支持1M上下文
  • Vue3实现视频播放弹窗组件,支持全屏播放,音量控制,进度条自定义样式,适配浏览器小窗播放,视频大小自适配,缓冲loading,代码复制即用
  • 合泰单片机怎么样
  • idea监控本地堆栈
  • Linux系统监控模块之Zabbix7添加监控主机
  • 生成式人工智能展望报告-欧盟-03-经济影响
  • 第一二章笔记
  • 同步时钟系统提升仓库自动化水平