• 【短信验证】手机登录短信验证


    如何设计?

    最初设计将生成验证码redis中存入 key 为手机号,value为验证码的键值对作为一个接口实现,但有问题是验证码不唯一,比如该手机号登录的验证码可以用于该手机号找回密码,这样肯定是不行的,后来尝试改用redis的hash结构,但需要前端配合传递 type 类型存入redis中,并且接口不能并发,最后采用生成不同类型验证码的多个接口实现,比如登录获取验证码为登录获取验证码接口,修改密码获取验证码为获取验证码接口,(采用 类型+手机号 的组合作为redis的key存入redis)

    逻辑

    接口一:生成验证码,存入redis,发送短信

    接口二:前端输入的验证码和redis中的验证码是否匹配


    生成6位验证码工具类

    1. /**
    2. * 生成(6位)验证码工具类
    3. */
    4. public class VerifyCodeUtils {
    5. public static String createCode(){
    6. return String.valueOf(ThreadLocalRandom.current().nextInt(100000, 999999));
    7. }
    8. }

    发送短信工具类(购买阿里云)

    需要获得短信签名,模板签名(或者appcode)

    1. /**
    2. *发送短信工具类
    3. */
    4. public class SmsUtils {
    5. /**
    6. * 仅仅完成将存入redis的验证码发送到目标手机上的短信功能
    7. * @param mob 手机号
    8. * @param code 后端生成的验证码
    9. */
    10. public static void sendMsg(String mob,String code){
    11. String host = "https://miitangs09.market.alicloudapi.com";
    12. String path = "/v1/tools/sms/code/sender";
    13. String method = "POST";
    14. String appcode = "填入购买服务时的appcode"; //购买服务的appcode,在历史订单中查看
    15. Map headers = new HashMap();
    16. //最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105
    17. headers.put("Authorization", "APPCODE " + appcode);
    18. //根据API的要求,定义相对应的Content-Type
    19. headers.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
    20. //需要给X-Ca-Nonce的值生成随机字符串,每次请求不能相同
    21. headers.put("X-Ca-Nonce", UUID.randomUUID().toString());
    22. Map querys = new HashMap();
    23. Map bodys = new HashMap();
    24. bodys.put("filterVirtual", "false");
    25. bodys.put("phoneNumber", mob);
    26. bodys.put("reqNo", "miitangtest01");
    27. bodys.put("smsSignId", "0000"); //签名id
    28. bodys.put("smsTemplateNo", "0001"); //短信模板id
    29. bodys.put("verifyCode", code); //验证码
    30. try {
    31. /**
    32. * 重要提示如下:
    33. * HttpUtils请从
    34. * https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/src/main/java/com/aliyun/api/gateway/demo/util/HttpUtils.java
    35. * 下载
    36. *
    37. * 相应的依赖请参照
    38. * https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/pom.xml
    39. */
    40. HttpResponse response = HttpUtils.doPost(host, path, method, headers, querys, bodys);
    41. //获取response的body
    42. System.out.println(EntityUtils.toString(response.getEntity()));
    43. } catch (Exception e) {
    44. e.printStackTrace();
    45. }
    46. }
    47. }

    手机验证码接口

    1. /**
    2. * 手机登录验证码接口
    3. *
    4. * @param phone 手机号.
    5. */
    6. @PublishMethod
    7. String LoginCode(String phone);

    手机验证码接口实现

    1. /**
    2. * 手机登录获取验证码的实现
    3. * 返回值为 redis 中的key (相同用户 不同验证码接口对于的 key 是不同的)
    4. * @param phone 手机号.
    5. * @return
    6. */
    7. @Override
    8. public String LoginCode(String phone) {
    9. AssertUtils.ThrowArgOutRangeException(phone.length(),"手机号码的长度必须为11",11,11);
    10. String code = VerifyCodeUtils.createCode(); //后台生成6位验证码
    11. System.out.println("手机登录后台生成的验证码:"+code);
    12. String key = RedisSmsEnum.Login.getKey() + phone; //拼接redis中唯一的key
    13. redisTemplate.opsForValue().set(key,code, 300, TimeUnit.SECONDS); //生成验证码放入redis中,设置5分钟过期时间
    14. System.out.println("存入redis的验证码"+redisTemplate.opsForValue().get(key));
    15. SmsUtils.sendMsg(phone,code); //发送(生成的验证码)到用户手机,暂时不开通,节约流量
    16. return key;
    17. }

    登录使用验证码逻辑

    1. /**
    2. * 用户手机登录的实现 .
    3. *
    4. * @param phone 手机号.
    5. * @param verifyCode 验证码.
    6. 6c8512064f11420f83d6f7c3f10816ba
    7. */
    8. @Override
    9. public void loginBySms(String phone, String verifyCode) {
    10. AssertUtils.ThrowArgNullException("手机号不能为空",phone,true);
    11. AssertUtils.ThrowArgNullException("验证码不能为空",verifyCode,true);
    12. AssertUtils.ThrowArgOutRangeException(phone.length(),"手机号码的长度必须为11",11,11);
    13. AssertUtils.ThrowArgOutRangeException(verifyCode.length(),"验证码长度必须为6",6,6);
    14. String newPhone = RedisSmsEnum.Login.getKey() + phone; //匹配唯一的redis中key(key为类型+电话号码的组合,保证key的唯一性)
    15. if (redisTemplate.opsForValue().get(newPhone) == null){
    16. throw new PsCoreRuntimeException("验证码过期");
    17. }
    18. if (!verifyCode.equals(redisTemplate.opsForValue().get(newPhone))){
    19. throw new PsCoreRuntimeException("验证码输入错误");
    20. }
    21. if (verifyCode.equals(redisTemplate.opsForValue().get(newPhone))){
    22. UserPOQueryPara para = new UserPOQueryPara();
    23. para.setParamByphone(phone);
    24. if (userPODao.queryList(para, 0, -1).size() == 0){
    25. throw new PsCoreRuntimeException("该用户不存在");
    26. }
    27. System.out.println("用户根据手机验证码登录成功");
    28. System.out.println("登录之后用户信息"+userPODao.queryList(para, 0, -1));
    29. redisTemplate.delete(newPhone); //登录成功之后 删除验证码
    30. }
    31. }

  • 相关阅读:
    JUC第十三讲:JUC锁: ReentrantLock详解
    EOS密钥被盗后如何恢复?
    百度智能云千帆Appbuilder全面升级!可玩性更强!速来体验!
    Multisim:JFET混频器设计(含完整程序)
    net-java-php-python-网上书店管理系统设计计算机毕业设计程序
    Linux-CentOS8-Oracle19c 安装详解
    【667. 优美的排列 II】
    1226:装箱问题 (贪心)
    git常用基础操作
    7个原则,看懂「深色模式」设计
  • 原文地址:https://blog.csdn.net/m0_46628950/article/details/128036418