短信验证码发送与校验

495 阅读2分钟

做一个短信验证码发送与校验的demo,就是我们常见的那种:输入手机号码,发送手机验证码,登录,只列了流程和代码,验证过了可以用。

有改进建议的朋友欢迎沟通。

短验发送流程

验证码发送流程.png

代码

/**
 * 发送短信验证码
 */
@PostMapping("/sendTextCode")
public AjaxResult sendTextCode(@RequestBody LoginBody loginBody) {
    log.info("发送验证码 开始");
    AjaxResult ajaxResult = authorizeService.sendTextCode(loginBody);
    log.info("发送验证码 结束");
    return ajaxResult;
}
​
​
/**
     * 发送短信验证码
     */
@Override
public AjaxResult sendTextCode(LoginBody loginBody) {
    String phoneNumber = loginBody.getPhoneNumber();
    String verifyKey = CacheConstants.TEXT_CODE_KEY + phoneNumber;
    log.info("短信验证码-verifyKey:{}", verifyKey);
    Long expire = redisCache.getExpire(verifyKey);
    log.info("短信验证码-verifyKey-{} 的剩余有效时长为:{}", verifyKey, expire);
    //未过期,不发送短信
    if (0 < expire) {
        log.info("短信验证码-verifyKey-{} 仍在有效期内", verifyKey);
        return AjaxResult.success("验证码仍在有效期内", phoneNumber);
    }
    //手机号码
    if (StringUtils.isEmpty(phoneNumber)) {
        log.error("手机号码不能为空");
        return AjaxResult.success("手机号码不能为空");
    }
    //accessKeyId
    String accessKeyId = sysConfigService.selectConfigByKey("sys.login.text.accessKeyId");
    log.info("短信服务-accessKeyId:{}", accessKeyId);
    if (StringUtils.isEmpty(accessKeyId)) {
        log.error("未配置'短信服务-accessKeyId',请联系管理员进行配置");
        return AjaxResult.success("验证码发送失败");
    }
    //accessKeySecret
    String accessKeySecret = sysConfigService.selectConfigByKey("sys.login.text.accessKeySecret");
    log.info("短信服务-accessKeySecret:{}", accessKeySecret);
    if (StringUtils.isEmpty(accessKeySecret)) {
        log.error("未配置'短信服务-accessKeySecret',请联系管理员进行配置");
        return AjaxResult.error("验证码发送失败");
    }
    //短信签名名称
    String signName = sysConfigService.selectConfigByKey("sys.login.text.signName");
    log.info("短信服务-signName:{}", signName);
    if (StringUtils.isEmpty(signName)) {
        log.error("未配置'短信服务-signName',请联系管理员进行配置");
        return AjaxResult.error("验证码发送失败");
    }
    //短信模板Code
    String templateCode = sysConfigService.selectConfigByKey("sys.login.text.templateCode");
    log.info("短信服务-templateCode:{}", templateCode);
    if (StringUtils.isEmpty(templateCode)) {
        log.error("未配置'短信服务-templateCode',请联系管理员进行配置");
        return AjaxResult.error("验证码发送失败");
    }
    //短信模板变量
    String templateParam = sysConfigService.selectConfigByKey("sys.login.text.templateParam");
    log.info("短信服务-templateParam:{}", templateParam);
    if (StringUtils.isEmpty(templateParam)) {
        log.error("未配置'短信服务-templateParam',请联系管理员进行配置");
        return AjaxResult.error("验证码发送失败");
    }
    String code = String.valueOf(1000 + new Random().nextInt(8999));
    log.info("生成4位随机验证码:{}", code);
    Map<String, String> templateParamMap = new HashMap<>();
    templateParamMap.put(templateParam, code);
    try {
        Client client = TextMsgUtil.createClient(accessKeyId, accessKeySecret);
        log.info("调用短信服务发送短信 开始");
        SendSmsRequest sendSmsRequest = new SendSmsRequest().setSignName(signName).setTemplateCode(templateCode).setPhoneNumbers(phoneNumber).setTemplateParam(JSON.toJSONString(templateParamMap));
        SendSmsResponse sendSmsResponse = client.sendSmsWithOptions(sendSmsRequest, new RuntimeOptions());
        Map<String, String> sendSmsHeaders = sendSmsResponse.getHeaders();
        log.info("短验发送响应头:{}", sendSmsHeaders);
        SendSmsResponseBody sendSmsBody = sendSmsResponse.getBody();
        String sendSmsCode = sendSmsBody.getCode();
        log.info("短验发送响应状态码:{}", sendSmsCode);
        String sendSmsMsg = sendSmsBody.getMessage();
        log.info("短验发送响应信息:{}", sendSmsBody.getMessage());
        if (!sendSmsCode.equalsIgnoreCase("OK")) {
            log.error("短验发送不成功,sendSmsCode:{},sendSmsMsg:{}", sendSmsCode, sendSmsMsg);
            return AjaxResult.error("验证码发送失败");
        }
    } catch (Exception e) {
        log.error("验证码发送失败", e);
        return AjaxResult.error("验证码发送失败");
    }
    log.info("保存验证码信息到缓存");
    redisCache.setCacheObject(verifyKey, code, Constants.TEXT_EXPIRATION, TimeUnit.MINUTES);
    return AjaxResult.success("验证码已发送", phoneNumber);
}

短验校验流程

验证码校验流程.jpg

/**
  * 校验短信验证码
  */
@PostMapping("/checkTextCode")
public AjaxResult checkTextCode(@RequestBody LoginBody loginBody) {
    log.info("校验短信验证码 开始");
    AjaxResult ajaxResult = authorizeService.checkTextCode(loginBody);
    log.info("校验短信验证码 结束");
    return ajaxResult;
}
​
@Override
public AjaxResult checkTextCode(LoginBody loginBody) {
    String phoneNumber = loginBody.getPhoneNumber();
    if (StringUtils.isEmpty(phoneNumber)) {
        log.error("电话号码为空");
        return AjaxResult.success("电话号码为空");
    }
    String textCode = loginBody.getTextCode();
    if (StringUtils.isEmpty(textCode)) {
        log.error("验证码为空");
        return AjaxResult.success("验证码为空");
    }
    log.info("发送短信的手机号码:{}", phoneNumber);
    String verifyKey = CacheConstants.TEXT_CODE_KEY + phoneNumber;
    String textCodeInCache = redisCache.getCacheObject(verifyKey);
    redisCache.deleteObject(verifyKey);
    if (StringUtils.isEmpty(textCode)) {
        log.error("缓存中未找到该手机号码对应的验证码");
        return AjaxResult.success("验证码已过期,请重新发送");
    }
    if (!textCode.equalsIgnoreCase(textCodeInCache)) {
        log.error("验证码不正确");
        return AjaxResult.success("验证码不正确,请重新输入");
    }
    return AjaxResult.success("验证通过", phoneNumber);
}