如何使用阿里云短信服务实现登录页面,手机验证码登录?1

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
短信服务,100条 3个月
简介: 如何使用阿里云短信服务实现登录页面,手机验证码登录?

1:个人如何使用阿里云短信服务?

2022如何使用个人阿里云短信服务?_linxiMY的博客-CSDN博客

添加完成之后,等待审核!一般2个小时就会出来审核结果了,这里我因为注册申请时填写规则有误,足足审核了7次才通过!点击进来以后,按照要求填写:因为一个账号只能选购一种,所以我这里就没法仔细演示了。然后点击添加即可,一把2-3个小时就可以申请出结果了。ConstantPropertiesUtils 工具类。点击登录阿里云短信服务控制台--->点击。3:创建一个SpringBoot 启动类。将下面的服务地址改为自己对应的地址。AccessKey 保存下来!4:添加一个配置工具类类。开启启动类调接口测试。

https://blog.csdn.net/XikYu/article/details/127617049?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522168232320316800192242795%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=168232320316800192242795&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-127617049-null-null.blog_rank_default&utm_term=%E9%98%BF%E9%87%8C%E4%BA%91&spm=1018.2226.3001.4450

2:直接上代码

2.1:建表SQL

CREATE TABLE `sys_user`
(
    `id`          varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'id',
    `username`    varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '用户名',
    `password`    varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '密码',
    `nickname`    varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '昵称',
    `email`       varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '邮箱',
    `phone`       varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '电话',
    `address`     varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '地址',
    `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
    `avatarUrl`   varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '头像',
    PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

2.2:后端代码

引入pom.xml 依 赖:

<dependencies>
    <dependency>
        <groupId>com.aliyun</groupId>
        <artifactId>aliyun-java-sdk-core</artifactId>
    </dependency>
</dependencies>

yml 文件:

server:
  port: 9999
spring:
  application:
    name: demo-end
  datasource:
    druid:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://127.0.0.1:3306/数据库?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
      username: root
      password: root
  redis:
    host: ip地址
    port: 6379
    lettuce:
      pool:
        max-active: 8 # ????
        max-idle: 8 # ??????
        min-idle: 0 # ??????
        max-wait: 100ms # ??????
mybatis:
  configuration:
    map-underscore-to-camel-case: true
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.xi.demoend.entity

application.properties:

aliyun.sms.regionId=default
aliyun.sms.accessKeyId=xxxxxx
aliyun.sms.secret=xxxxxx

common公共包下的类:

全局统一返回结果:

package com.xialj.demoend.common;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
 * @Author 
 * @Date Created in  2023/2/23 17:25
 * @DESCRIPTION:  全局统一返回结果
 * @Version V1.0
 */
@Data
@ApiModel(value = "全局统一返回结果")
@SuppressWarnings("all")
public class Result<T> {
    @ApiModelProperty(value = "返回码")
    private Integer code;
    @ApiModelProperty(value = "返回消息")
    private String message;
    @ApiModelProperty(value = "返回数据")
    private T data;
    private Long total;
    public Result(){}
    protected static <T> Result<T> build(T data) {
        Result<T> result = new Result<T>();
        if (data != null)
            result.setData(data);
        return result;
    }
    public static <T> Result<T> build(T body, ResultCodeEnum resultCodeEnum) {
        Result<T> result = build(body);
        result.setCode(resultCodeEnum.getCode());
        result.setMessage(resultCodeEnum.getMessage());
        return result;
    }
    public static <T> Result<T> build(Integer code, String message) {
        Result<T> result = build(null);
        result.setCode(code);
        result.setMessage(message);
        return result;
    }
    public static<T> Result<T> ok(){
        return Result.ok(null);
    }
    /**
     * 操作成功
     * @param data
     * @param <T>
     * @return
     */
    public static<T> Result<T> ok(T data){
        Result<T> result = build(data);
        return build(data, ResultCodeEnum.SUCCESS);
    }
    public static<T> Result<T> fail(){
        return Result.fail(null);
    }
    /**
     * 操作失败
     * @param data
     * @param <T>
     * @return
     */
    public static<T> Result<T> fail(T data){
        Result<T> result = build(data);
        return build(data, ResultCodeEnum.FAIL);
    }
    public Result<T> message(String msg){
        this.setMessage(msg);
        return this;
    }
    public Result<T> code(Integer code){
        this.setCode(code);
        return this;
    }
    public boolean isOk() {
        if(this.getCode().intValue() == ResultCodeEnum.SUCCESS.getCode().intValue()) {
            return true;
        }
        return false;
    }
}

统一返回结果状态信息类:

package com.xialj.demoend.common;
import lombok.Getter;
/**
   * @Author 
   * @Date Created in  2023/2/23 17:25
   * @DESCRIPTION:  统一返回结果状态信息类
   * @Version V1.0
   */
@Getter
@SuppressWarnings("all")
public enum ResultCodeEnum {
    SUCCESS(200,"成功"),
    FAIL(201, "失败"),
    PARAM_ERROR( 202, "参数不正确"),
    SERVICE_ERROR(203, "服务异常"),
    DATA_ERROR(204, "数据异常"),
    DATA_UPDATE_ERROR(205, "数据版本异常"),
    LOGIN_AUTH(208, "未登陆"),
    PERMISSION(209, "没有权限"),
    CODE_ERROR(210, "验证码错误"),
//    LOGIN_MOBLE_ERROR(211, "账号不正确"),
    LOGIN_DISABLED_ERROR(212, "改用户已被禁用"),
    REGISTER_MOBLE_ERROR(213, "手机号码格式不正确"),
    REGISTER_MOBLE_ERROR_NULL(214, "手机号码为空"),
    LOGIN_AURH(214, "需要登录"),
    LOGIN_ACL(215, "没有权限"),
    URL_ENCODE_ERROR( 216, "URL编码失败"),
    ILLEGAL_CALLBACK_REQUEST_ERROR( 217, "非法回调请求"),
    FETCH_ACCESSTOKEN_FAILD( 218, "获取accessToken失败"),
    FETCH_USERINFO_ERROR( 219, "获取用户信息失败"),
    //LOGIN_ERROR( 23005, "登录失败"),
    PAY_RUN(220, "支付中"),
    CANCEL_ORDER_FAIL(225, "取消订单失败"),
    CANCEL_ORDER_NO(225, "不能取消预约"),
    HOSCODE_EXIST(230, "医院编号已经存在"),
    NUMBER_NO(240, "可预约号不足"),
    TIME_NO(250, "当前时间不可以预约"),
    SIGN_ERROR(300, "签名错误"),
    HOSPITAL_OPEN(310, "医院未开通,暂时不能访问"),
    HOSPITAL_LOCK(320, "医院被锁定,暂时不能访问"),
    HOSPITAL_LOCKKEY(330,"医院对应key不一致")
    ;
    private Integer code;
    private String message;
    private ResultCodeEnum(Integer code, String message) {
        this.code = code;
        this.message = message;
    }
}

untils包下的工具类:

ConstantPropertiesUtils 用来读取 application.properties文件中的配置

package com.xialj.demoend.utils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
 * @Author 
 * @Date Created in  2023/2/23 17:25
 * @DESCRIPTION:
 * @Version V1.0
 */
@Component
public class ConstantPropertiesUtils implements InitializingBean {
    //InitializingBean  初始化bean  让spring 容器一初始化就加载
    @Value("${aliyun.sms.regionId}")
    private String regionId;
    @Value("${aliyun.sms.accessKeyId}")
    private String accessKeyId;
    @Value("${aliyun.sms.secret}")
    private String secret;
    public static String REGION_Id;
    public static String ACCESS_KEY_ID;
    public static String SECRECT;
    @Override
    public void afterPropertiesSet() throws Exception {
        REGION_Id=regionId;
        ACCESS_KEY_ID=accessKeyId;
        SECRECT=secret;
    }
}

RandomUtil 工具类用来生成6位验证码:

package com.xialj.demoend.utils;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
/**
 * @Author 
 * @Date Created in  2023/2/23 17:25
 * @DESCRIPTION:
 * @Version V1.0
 */
@SuppressWarnings("ALL")
public class RandomUtil {
    private static final Random random = new Random();
    private static final DecimalFormat fourdf = new DecimalFormat("0000");
    private static final DecimalFormat sixdf = new DecimalFormat("000000");
    public static String getFourBitRandom() {
        return fourdf.format(random.nextInt(10000));
    }
    public static String getSixBitRandom() {
        return sixdf.format(random.nextInt(1000000));
    }
    /**
     * 给定数组,抽取n个数据
     * @param list
     * @param n
     * @return
     */
    public static ArrayList getRandom(List list, int n) {
        Random random = new Random();
        HashMap<Object, Object> hashMap = new HashMap<Object, Object>();
// 生成随机数字并存入HashMap
        for (int i = 0; i < list.size(); i++) {
            int number = random.nextInt(100) + 1;
            hashMap.put(number, i);
        }
// 从HashMap导入数组
        Object[] robjs = hashMap.values().toArray();
        ArrayList r = new ArrayList();
// 遍历数组并打印数据
        for (int i = 0; i < n; i++) {
            r.add(list.get((int) robjs[i]));
            System.out.print(list.get((int) robjs[i]) + "\t");
        }
        System.out.print("\n");
        return r;
    }
}

User实体类:(实现了简单的手机验证码登录+email邮箱登录)

package com.xialj.demoend.entity;
import com.alibaba.druid.sql.visitor.functions.Insert;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
 * @Author 
 * @Date Created in  2023/2/24 13:07
 * @DESCRIPTION:   User 实体类
 * @Version V1.0
 */
@Data
public class User extends PageQuery implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * id
     */
    private String id;
    /**
     * 用户名
     */
    private String username;
    /**
     * 密码
     */
    private String password;
    /**
     * 昵称
     */
    private String nickname;
    /**
     * 邮箱
     */
    @ApiModelProperty(value = "联系人邮箱")
    @NotBlank(message = "邮箱不能为空", groups = {Insert.class})
    @NotNull(message = "邮箱不能为空", groups = {Insert.class})
    @Pattern(regexp = ".+@.+\\.com$", message = "Email格式不正确")
    private String email;
    /**
     * 电话
     */
    @ApiModelProperty(value = "联系人电话")
    @NotBlank(message = "手机号码不能为空", groups = {Insert.class})
    @NotNull(message = "手机号不能为空", groups = {Insert.class})
    @Length(min = 11, max = 11, message = "手机号只能为11位")
    @Pattern(regexp = "^[1][3,4,5,6,7,8,9][0-9]{9}$", message = "手机号格式有误")
    private String phone;
    /**
     * 地址
     */
    private String address;
    /**
     * 验证码
     */
    private Integer code;
    /**
     * 创建时间
     */
    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
    private Date createTime;
    /**
     * 头像
     */
    private String avatarUrl;
}

MsmApiController:用来实现发送验证码的接口

package com.xialj.demoend.controller;
import cn.hutool.extra.mail.MailUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.xialj.demoend.common.Result;
import com.xialj.demoend.common.ResultCodeEnum;
import com.xialj.demoend.common.paramCommon;
import com.xialj.demoend.entity.User;
import com.xialj.demoend.service.MsmService;
import com.xialj.demoend.utils.JsonSerializer;
import com.xialj.demoend.utils.RandomUtil;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.mail.MessagingException;
import javax.validation.constraints.Email;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
 * @Author xlj
 * @Date Created in  2023/2/23 17:25
 * @DESCRIPTION:  主要是为了实现邮箱发送验证码,以及手机发送验证码登录
 * @Version V1.0
 */
@RestController
@RequestMapping("/api/msm")
@SuppressWarnings("ALL")
@Slf4j
@CrossOrigin
public class MsmApiController {
    @Autowired
    private MsmService msmService;
    @Autowired
    private RedisTemplate<String,String> redisTemplate;
    //将手机验证码存放到redis  中,并设置过期时间
    @ApiOperation(value = "发送手机验证码")
    @PostMapping("sendPhoneCode")
    public Result sendCode(@RequestBody(required = true) @Validated User user){
        String phoneNum = user.getPhone();
        // phone  作为redis  中的key,  code  作为redis  中的value值
        String code = redisTemplate.opsForValue().get(phoneNum);
        if (!StringUtils.isEmpty(code)) {
            //这里为什么从redis 拿取 验证码  我理解的是 ,因为redis 验证码我们给他设置了时间限制,所以在规定时间内,验证码
            //可以多次使用,一旦时间到期之后,我们就需要从新生成6位数的验证码了。
            return Result.ok(code);
        }
        //生成六位验证码
        code = RandomUtil.getSixBitRandom();
        //调用service 方法,整合阿里云短信服务进行发送
        Boolean isSend = msmService.send(phoneNum,code);
        //返回的Boolean 值进行判断 ,如果发送信息成功,即存入到redis 中,如果没有则提示验证码发送失败
        if (isSend) {
            //放到redis中规定时间内有效
            redisTemplate.opsForValue().set(phoneNum,code,1, TimeUnit.MINUTES);
            redisTemplate.setDefaultSerializer(new JsonSerializer<>());
//            redisTemplate.opsForValue().set(phoneNum,code);
            String codeMessage = redisTemplate.opsForValue().get(phoneNum);
            Set<String> allKeys = redisTemplate.keys("*");
            for (String key : allKeys) {
                System.out.println(key);
                System.out.println(key.getClass().getName());
            }
            log.info("当前存储的验证码为:{}",codeMessage);
            return Result.ok(code);
        } else {
            return Result.fail().message(paramCommon.FAIL_MESSAGE);
        }
    }
}

MsmServiceImpl实现类:

package com.hospital.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.CommonRequest;
import com.aliyuncs.CommonResponse;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.exceptions.ServerException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.hospital.service.MsmService;
import com.hospital.utils.ConstantPropertiesUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.HashMap;
import java.util.Map;
@Service
public class MsmServiceImpl implements MsmService {
    //根据手机号,存入验证码
    @Override
    public Boolean send(String phone, String code) {
        //判断手机号是否为空
        if (StringUtils.isEmpty(phone)) {
            return false;
        }
        //整合阿里云的短信服务
        DefaultProfile profile = DefaultProfile.
                getProfile(ConstantPropertiesUtils.REGION_Id,
                        ConstantPropertiesUtils.ACCESS_KEY_ID,
                        ConstantPropertiesUtils.SECRECT);
        IAcsClient client = new DefaultAcsClient(profile);
        CommonRequest request = new CommonRequest();
        //request.setProtocol(ProtocolType.HTTPS);
        request.setMethod(MethodType.POST);
        request.setDomain("dysmsapi.aliyuncs.com");
        request.setVersion("2017-05-25");
        request.setAction("SendSms");
//        request.setSysAction();
        //手机号
        request.putQueryParameter("PhoneNumbers", phone);
        //签名名称
        request.putQueryParameter("SignName", "自己申请的短信签名");
        //模板code
        request.putQueryParameter("TemplateCode", "短信模板CODE");
        //验证码  使用json格式   {"code":"123456"}
        Map<String,Object> param = new HashMap();
        param.put("code",code);
        request.putQueryParameter("TemplateParam", JSONObject.toJSONString(param));
        //调用方法进行短信发送
        try {
            CommonResponse response = client.getCommonResponse(request);
            System.out.println(response.getData());
            return response.getHttpResponse().isSuccess();
        } catch (ServerException e) {
            e.printStackTrace();
        } catch (ClientException e) {
            e.printStackTrace();
        }
        return false;
    }
}


目录
相关文章
|
1月前
|
自然语言处理 监控 安全
2025年阿里云短信验证码价格多少钱?计费模式与场景选型指南
随着企业数字化转型,短信验证码作为用户身份验证的重要工具,其成本与效率的平衡至关重要。阿里云短信服务以高可靠性、灵活计费和多场景适配著称。按量付费模式适合需求波动大的场景,而短信套餐包则为长期稳定需求提供了成本优势。针对不同业务场景,如高频验证、跨境业务及中小型企业轻量级需求,阿里云提供了定制化的选型策略。此外,通过阶梯定价、防盗刷监控等措施实现成本优化与风险规避,并不断进行技术升级以确保服务的安全性和稳定性。根据2025年最新数据,企业可根据自身需求选择最适合的阿里云短信验证码服务方案。
|
6月前
|
数据采集 监控 安全
阿里云短信服务+图形认证,有效降低验证码盗刷概率
阿里云短信服务+图形认证服务,有效降低验证码盗刷概率。
563 3
阿里云短信服务+图形认证,有效降低验证码盗刷概率
|
1月前
|
缓存 Java 应用服务中间件
java语言后台管理若依框架-登录提示404-接口异常-系统接口404异常如何处理-登录验证码不显示prod-api/captchaImage 404 (Not Found) 如何处理-解决方案优雅草卓伊凡
java语言后台管理若依框架-登录提示404-接口异常-系统接口404异常如何处理-登录验证码不显示prod-api/captchaImage 404 (Not Found) 如何处理-解决方案优雅草卓伊凡
172 5
|
7月前
|
存储 NoSQL 数据库
认证服务---整合短信验证码,用户注册和登录 ,密码采用MD5加密存储 【二】
这篇文章讲述了在分布式微服务系统中添加用户注册和登录功能的过程,重点介绍了用户注册时通过远程服务调用第三方服务获取短信验证码、使用Redis进行验证码校验、对密码进行MD5加密后存储到数据库,以及用户登录时的远程服务调用和密码匹配校验的实现细节。
认证服务---整合短信验证码,用户注册和登录 ,密码采用MD5加密存储 【二】
|
5月前
Discuz! X3.5插件云诺-阿里云短信手机登录 会员登录后也无法查看附件图片的问题解决方法
Discuz! X3.5插件云诺-阿里云短信手机登录 会员登录后也无法查看附件图片的问题解决方法
90 2
|
5月前
|
安全 API PHP
港澳台验证码海外短信群发教程,利用阿里云国际如何实现境外短信操作
港澳台验证码海外短信群发教程,利用阿里云国际如何实现境外短信操作
|
5月前
|
C#
C# 图形验证码实现登录校验代码
C# 图形验证码实现登录校验代码
171 2
|
5月前
|
Java
Java 登录输入的验证码
Java 登录输入的验证码
60 1
|
7月前
|
资源调度 JavaScript API
nest.js + sms 实现短信验证码登录
本文介绍了在Nest.js框架中集成短信验证码登录的实现方案,详细阐述了使用阿里云短信服务的配置流程、资质申请、短信模板设置,并提供了API调用示例和工程代码的运行步骤。
nest.js + sms 实现短信验证码登录
|
6月前
|
存储 JSON 前端开发
node使用token来实现前端验证码和登录功能详细流程[供参考]=‘很值得‘
本文介绍了在Node.js中使用token实现前端验证码和登录功能的详细流程,包括生成验证码、账号密码验证以及token验证和过期处理。
149 0
node使用token来实现前端验证码和登录功能详细流程[供参考]=‘很值得‘

热门文章

最新文章

  • 1
    阿里云采购季:短信服务低至 0.01 元/条!
  • 2
    【01】整体试验思路,如何在有UID的情况下获得用户手机号信息,python开发之理论研究试验,如何通过抖音视频下方的用户的UID获得抖音用户的手机号-本系列文章仅供学习研究-禁止用于任何商业用途-仅供学习交流-优雅草卓伊凡
  • 3
    【02】整体试验思路,在这之前我们发现sec_uid,sec_uid是什么和uid的关系又是什么?相互如何转换?python开发之理论研究试验,如何通过抖音视频下方的用户的UID获得抖音用户的手机号-本系列文章仅供学习研究-禁止用于任何商业用途-仅供学习交流-优雅草卓伊凡
  • 4
    【03】鸿蒙实战应用开发-华为鸿蒙纯血操作系统Harmony OS NEXT-测试hello word效果-虚拟华为手机真机环境调试-为DevEco Studio编译器安装中文插件-测试写一个滑动块效果-介绍诸如ohos.ui等依赖库-全过程实战项目分享-从零开发到上线-优雅草卓伊凡
  • 5
    算法系统协同优化,vivo与港中文推出BlueLM-V-3B,手机秒变多模态AI专家
  • 6
    实时获取短信发送状态,这个功能别错过!|阿里云短信服务
  • 7
    MNN-LLM App:在手机上离线运行大模型,阿里巴巴开源基于 MNN-LLM 框架开发的手机 AI 助手应用
  • 8
    OmAgent:轻松构建在终端设备上运行的 AI 应用,赋能手机、穿戴设备、摄像头等多种设备
  • 9
    美团面试:手机扫描PC二维码登录,底层原理和完整流程是什么?
  • 10
    ClKLog支持手机端查询统计数据啦!