谷粒商城----认证服务

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: 谷粒商城----认证服务

一、短信验证码(阿里云短信服务)

@Data
@ConfigurationProperties(prefix = "spring.cloud.alicloud.sms")
@Component
public class SmsComponent {
  private String host;
  private String path;
  private String skin;
  private String sign;
  private String appCode;
  public String sendSmsCode(String phone, String code){
    String method = "GET";
    Map<String, String> headers = new HashMap<String, String>();
    //最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105
    headers.put("Authorization", "APPCODE " + this.appCode);
    Map<String, String> querys = new HashMap<String, String>();
    querys.put("code", code);
    querys.put("phone", phone);
    querys.put("skin", this.skin);
    querys.put("sign", this.sign);
    HttpResponse response = null;
    try {
      response = HttpUtils.doGet(this.host, this.path, method, headers, querys);
      //获取response的body
      if(response.getStatusLine().getStatusCode() == 200){
        return EntityUtils.toString(response.getEntity());
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
    return "fail_" + response.getStatusLine().getStatusCode();
  }
}

二、验证码防刷校验

@Controller
@RequestMapping("/sms")
public class SmsSendController {
  @Autowired
  private SmsComponent smsComponent;
  /*** 提供给别的服务进行调用的
   */
  @GetMapping("/sendcode")
  public R sendCode(@RequestParam("phone") String phone, @RequestParam("code") String code){
    if(!"fail".equals(smsComponent.sendSmsCode(phone, code).split("_")[0])){
      return R.ok();
    }
    return R.error(BizCodeEnum.SMS_SEND_CODE_EXCEPTION.getCode(), BizCodeEnum.SMS_SEND_CODE_EXCEPTION.getMsg());
  }
}

🚩思路是将每一次发的验证码存在redis,并且加上存放的当前时间,下一次发验证码请求时先判断当前时间-上一次存放时间,如果小于60秒,返回错误,否则才发验证码请求

/** 接收到一个手机号,在此处生成验证码和缓存,然后转给第三方服务让他给手机发验证按
   * */
  @ResponseBody
  @GetMapping("/sms/sendcode")
  public R sendCode(@RequestParam("phone") String phone){
    //  TODO 接口防刷(冷却时长递增),redis缓存 sms:code:电话号
    String redisCode = stringRedisTemplate.opsForValue().get(AuthServerConstant.SMS_CODE_CACHE_PREFIX + phone);
    // 如果不为空,返回错误信息
    if(null != redisCode && redisCode.length() > 0){
      long CuuTime = Long.parseLong(redisCode.split("_")[1]);
      if(System.currentTimeMillis() - CuuTime < 60 * 1000){ // 60s
        return R.error(BizCodeEnum.SMS_CODE_EXCEPTION.getCode(), BizCodeEnum.SMS_CODE_EXCEPTION.getMsg());
      }
    }
    // 生成验证码
    String code = UUID.randomUUID().toString().substring(0, 6);
    String redis_code = code + "_" + System.currentTimeMillis();
    // 缓存验证码
    stringRedisTemplate.opsForValue().set(AuthServerConstant.SMS_CODE_CACHE_PREFIX + phone, redis_code , 10, TimeUnit.MINUTES);
    try {// 调用第三方短信服务
      return thirdPartFeignService.sendCode(phone, code);
    } catch (Exception e) {
      log.warn("远程调用不知名错误 [无需解决]");
    }
    return R.ok();
  }

三、注册环境

@PostMapping("/register")
  public String register(@Valid UserRegisterVo userRegisterVo,
               BindingResult result,
               RedirectAttributes redirectAttributes){
    if(result.hasErrors()){
      // 将错误属性与错误信息一一封装
      Map<String, String> errors = result.getFieldErrors().stream().collect(
          Collectors.toMap(FieldError::getField, fieldError -> fieldError.getDefaultMessage()));
      // addFlashAttribute 这个数据只取一次
      redirectAttributes.addFlashAttribute("errors", errors);
      return "redirect:http://auth.gulimall.com/reg.html";
    }
/**
   * TODO 重定向携带数据,利用session原理 将数据放在sessoin中 取一次之后删掉
   *
   * TODO 1. 分布式下的session问题
   * 校验
   * RedirectAttributes redirectAttributes : 模拟重定向带上数据
   */
  @PostMapping("/register")
  public String register(@Valid UserRegisterVo userRegisterVo,
               BindingResult result,
               RedirectAttributes redirectAttributes){
    if(result.hasErrors()){
      // 将错误属性与错误信息一一封装
      Map<String, String> errors = result.getFieldErrors().stream().collect(
          Collectors.toMap(FieldError::getField, FieldError::getDefaultMessage));
      // addFlashAttribute 这个数据只取一次
      redirectAttributes.addFlashAttribute("errors", errors);
      return "redirect:http://auth.gulimall.com/reg.html";
    }
    // 开始注册 调用远程服务
    // 1.校验验证码
    String code = userRegisterVo.getCode();
    String redis_code = stringRedisTemplate.opsForValue().get(AuthServerConstant.SMS_CODE_CACHE_PREFIX + userRegisterVo.getPhone());
    if(!StringUtils.isEmpty(redis_code)){
      // 验证码通过
      if(code.equals(redis_code.split("_")[0])){
        // 删除验证码
        stringRedisTemplate.delete(AuthServerConstant.SMS_CODE_CACHE_PREFIX + userRegisterVo.getPhone());
        // 调用远程服务进行注册
        R r = memberFeignService.register(userRegisterVo);
        if(r.getCode() == 0){
          // 注册成功,去登录
          return "redirect:http://auth.gulimall.com/login.html";
        }else{
          Map<String, String> errors = new HashMap<>();
          errors.put("msg",r.getData("msg",new TypeReference<String>(){}));
          // 数据只需要取一次
          redirectAttributes.addFlashAttribute("errors",errors);
          return "redirect:http://auth.gulimall.com/reg.html";
        }
      }else{
        Map<String, String> errors = new HashMap<>();
        errors.put("code", "验证码错误");
        // addFlashAttribute 这个数据只取一次
        redirectAttributes.addFlashAttribute("errors", errors);
        return "redirect:http://auth.gulimall.com/reg.html";
      }
    }else{
      Map<String, String> errors = new HashMap<>();
      errors.put("code", "验证码错误");
      // addFlashAttribute 这个数据只取一次
      redirectAttributes.addFlashAttribute("errors", errors);
      return "redirect:http://auth.gulimall.com/reg.html";
    }
  }
相关文章
|
JavaScript Java 应用服务中间件
谷粒商城:认证服务准备+60s短信验证
谷粒商城:认证服务准备+60s短信验证
《阿里云产品手册2022-2023 版》——号码认证服务
《阿里云产品手册2022-2023 版》——号码认证服务
194 0
|
移动开发 API 开发工具
秒懂云通信:如何使用阿里云号码认证服务(小白指南)
手把手教你如何使用阿里云号码认证服务,超详细控制台步骤解析,快速上手!
3397 0
秒懂云通信:如何使用阿里云号码认证服务(小白指南)
|
安全 数据安全/隐私保护 开发者
阿里云通信发布全新号码认证服务, 重新定义手机号码认证的方式
12月12日,阿里云通信宣布号码认证服务正式商用,将重新定义手机号码认证的方式。因移动应用实名制的政策要求,手机号码认证在移动APP的注册、登录等场景用的越来越多。而对于开发者来说,能完成手机号码认证的选择并不多,一般是借助短信、语音的基础通信通道,自己实现短信验证码或语音验证码来实现。
25187 0
|
存储 算法 调度
第六章 输入输出系统【操作系统】1
第六章 输入输出系统【操作系统】1
372 0
|
前端开发 Java Docker
利用 docker 部署 elasticsearch 集群(单节点多实例)
利用 docker 部署 elasticsearch 集群(单节点多实例)
783 0
|
消息中间件 Java 中间件
秒懂消息队列MQ,万字总结带你全面了解消息队列MQ
消息队列是大型分布式系统不可缺少的中间件,也是高并发系统的基石中间件,所以掌握好消息队列MQ就变得极其重要。接下来我就将从零开始介绍什么是消息队列?消息队列的应用场景?如何进行选型?如何在Spring Boot项目中整合集成消息队列。
24327 10
秒懂消息队列MQ,万字总结带你全面了解消息队列MQ
|
存储 NoSQL Java