阿里云短信验证码服务

时间:2024-7-24    作者:老大夫    分类: 尚庭公寓


7.4.2.2 接口开发

首先在LoginController中注入LoginService,如下

@RestController
@Tag(name = "登录管理")
@RequestMapping("/app/")
public class LoginController {

    @Autowired
    private LoginService service;
}
1. 获取短信验证码

该接口需向登录手机号码发送短信验证码,各大云服务厂商都提供短信服务,本项目使用阿里云完成短信验证码功能,下面介绍具体配置。

  • 配置短信服务

    • 开通短信服务

    • 阿里云官网,注册阿里云账号,并按照指引,完成实名认证(不认证,无法购买服务)

    • 找到短信服务,选择免费开通

    • 进入短信服务控制台,选择快速学习和测试

    • 找到发送测试下的API发送测试,绑定测试用的手机号(只有绑定的手机号码才能收到测试短信),然后配置短信签名和短信模版,这里选择[专用]测试签名/模版

    • 创建AccessKey

    云账号 AccessKey 是访问阿里云 API 的密钥,没有AccessKey无法调用短信服务。点击页面右上角的头像,选择AccessKey管理,然后创建AccessKey

    image-20230808104345383
  • 配置所需依赖

    如需调用阿里云的短信服务,需使用其提供的SDK,具体可参考官方文档

    common模块的pom.xml文件中增加如下内容

    <dependency>
      <groupId>com.aliyun</groupId>
      <artifactId>dysmsapi20170525</artifactId>
    </dependency>
  • 配置发送短信客户端

    • application.yml中增加如下内容
    aliyun:
      sms:
        access-key-id: <access-key-id>
        access-key-secret: <access-key-secret>
        endpoint: dysmsapi.aliyuncs.com

    注意

    上述access-key-idaccess-key-secret需根据实际情况进行修改。

    • common模块中创建com.atguigu.lease.common.sms.AliyunSMSProperties类,内容如下
    @Data
    @ConfigurationProperties(prefix = "aliyun.sms")
    public class AliyunSMSProperties {
    
        private String accessKeyId;
    
        private String accessKeySecret;
    
        private String endpoint;
    }
    • common模块中创建com.atguigu.lease.common.sms.AliyunSmsConfiguration类,内容如下
    @Configuration
    @EnableConfigurationProperties(AliyunSMSProperties.class)
    @ConditionalOnProperty(name = "aliyun.sms.endpoint")
    public class AliyunSMSConfiguration {
    
        @Autowired
        private AliyunSMSProperties properties;
    
        @Bean
        public Client smsClient() {
            Config config = new Config();
            config.setAccessKeyId(properties.getAccessKeyId());
            config.setAccessKeySecret(properties.getAccessKeySecret());
            config.setEndpoint(properties.getEndpoint());
            try {
                return new Client(config);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
    
        }
    }
  • 配置Redis连接参数

    spring: 
    data:
      redis:
        host: 192.168.10.101
        port: 6379
        database: 0
  • 编写Controller层逻辑

    LoginController中增加如下内容

    @GetMapping("login/getCode")
    @Operation(summary = "获取短信验证码")
    public Result getCode(@RequestParam String phone) {
      service.getSMSCode(phone);
      return Result.ok();
    }
  • 编写Service层逻辑

    • 编写发送短信逻辑

    • SmsService中增加如下内容

      void sendCode(String phone, String verifyCode);
    • SmsServiceImpl中增加如下内容

      @Override
      public void sendCode(String phone, String code) {
      
        SendSmsRequest smsRequest = new SendSmsRequest();
        smsRequest.setPhoneNumbers(phone);
        smsRequest.setSignName("阿里云短信测试");
        smsRequest.setTemplateCode("SMS_154950909");
        smsRequest.setTemplateParam("{\"code\":\"" + code + "\"}");
        try {
            client.sendSms(smsRequest);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
      }
    • 编写生成随机验证码逻辑

    common模块中创建com.atguigu.lease.common.utils.VerifyCodeUtil类,内容如下

    public class VerifyCodeUtil {
        public static String getVerifyCode(int length) {
            StringBuilder builder = new StringBuilder();
            Random random = new Random();
            for (int i = 0; i < length; i++) {
                builder.append(random.nextInt(10));
            }
            return builder.toString();
        }
    }
    • 编写获取短信验证码逻辑

    • LoginServcie中增加如下内容

      void getSMSCode(String phone);
    • LoginServiceImpl中增加如下内容

      @Override
      public void getSMSCode(String phone) {
      
        //1. 检查手机号码是否为空
        if (!StringUtils.hasText(phone)) {
            throw new LeaseException(ResultCodeEnum.APP_LOGIN_PHONE_EMPTY);
        }
      
        //2. 检查Redis中是否已经存在该手机号码的key
        String key = RedisConstant.APP_LOGIN_PREFIX + phone;
        boolean hasKey = redisTemplate.hasKey(key);
        if (hasKey) {
            //若存在,则检查其存在的时间
            Long expire = redisTemplate.getExpire(key, TimeUnit.SECONDS);
            if (RedisConstant.APP_LOGIN_CODE_TTL_SEC - expire < RedisConstant.APP_LOGIN_CODE_RESEND_TIME_SEC) {
                //若存在时间不足一分钟,响应发送过于频繁
                throw new LeaseException(ResultCodeEnum.APP_SEND_SMS_TOO_OFTEN);
            }
        }
      
        //3.发送短信,并将验证码存入Redis
        String verifyCode = VerifyCodeUtil.getVerifyCode(6);
        smsService.sendCode(phone, verifyCode);
        redisTemplate.opsForValue().set(key, verifyCode, RedisConstant.APP_LOGIN_CODE_TTL_SEC, TimeUnit.SECONDS);
      }

      注意

      需要注意防止频繁发送短信。


扫描二维码,在手机上阅读

推荐阅读: