@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";
}
}