一、短信验证码(阿里云短信服务)
@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"; } }