java实现手机号验证码登录功能,并限制同一个IP10分钟以内最多发3次。保姆级教程

2023-10-26

​​​​​​​第一步:引入依赖

        <!--redis-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
      <!--阿里云短信服务-->
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>aliyun-java-sdk-core</artifactId>
            <version>4.5.16</version>
        </dependency>
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>aliyun-java-sdk-ecs</artifactId>
            <version>4.17.6</version>
        </dependency>

第二步:在yml中配置redis以及阿里云短信服务秘钥

spring:
  redis:
    # tw:database1,2 联调1,开发2
    database: 10
    host: 127.0.0.1
    port: 6379  
    timeout: 60000
    jedis:
      pool:
        max-idle: 8
        max-wait: -1
        min-idle: 0
aliyyun:
  sms:
    access-key: *******************  //替换自己的
    access-secret: ****************  //替换自己的

第三部:开始编写代码(需要两个接口一个获取验证码的接口,一个登录校验验证码的接口)

第一个接口如下:

 controller 

    /**
     * description : 发送短信验证码
     *
     */
    @PostMapping(value = "/genRandom", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public CommonResponse genRandom(@RequestBody SmsLogin smsLogin, HttpServletRequest request) throws Exception {
        String clientIp = IpUtil.getClientIP(request);
        Map genRandom = smsService.genRandom(smsLogin, clientIp);
        return new CommonResponse(genRandom);
    }

 
service

    /**
     * description : 发送短信验证码
     *
     */
    Map  genRandom(SmsLogin smsLogin,String clientIp) throws Exception;




    /**
     * description : 发送短信验证码
     *
     */
    public Map  genRandom(SmsLogin smsLogin,String clientIp) throws Exception {
         //入参校验
        ValidationResponseEnum.PHONE_NUMBER.assertNotEmpty(smsLogin.getPhoneNumber());
        if (!isMobile(smsLogin.getPhoneNumber())) {
            throw new BaseException(1001,"手机号码格式错误,请更换后重试");
        }
        //发送参数
        AliyunSms aliyunSms = this.aliyunSMS(smsLogin.getPhoneNumber());
        // 发送验证码
        return this.sendAliyunMsg(aliyunSms,clientIp);
    }



    /**
     * description : 发送短信验证码-发送参数
     *
     */
    private AliyunSms aliyunSMS(String phoneNumber) {
        AliyunSms aliyun = new AliyunSms();
        // 签名
        aliyun.setSignName(AliyunConstant.ALIYUN_SMS_SIGNNAME);
        // 模板编码
        aliyun.setTemplateCode(AliyunConstant.ALIYUN_SMS_TEMPLATECODE);
        // 失效时间
        aliyun.setTimeout(AliyunConstant.ALIYUN_SMS_TIMEOUT);
        // 验证码长度
        aliyun.setVerifySize(AliyunConstant.ALIYUN_SMS_VERIFY_SIZE);
        // 手机号
        aliyun.setPhoneNumber(phoneNumber);
        return aliyun;
    }




    /**
     * description : 发送短信验证码-阿里云发送
     *
     */
    public Map  sendAliyunMsg(AliyunSms aliyunSms,String clientIp) throws Exception {
        //检查同一IP10分钟内发送次数是否超限制
        String countKey = "ip_count:" + clientIp;
        if (redisTemplate.opsForValue().get(countKey)== null) {
            //首次发送
            redisTemplate.opsForValue().set(countKey, "1", 10, TimeUnit.MINUTES);
        }else{
            //获取发送次数
            Integer count = Integer.valueOf(redisTemplate.opsForValue().get(countKey));
            if (count != null && count >= 3) {
                throw new BaseException (1005,"频繁发送,请10分钟后重试");
            }
            count++;
            // 增加发送次数
           // redisTemplate.opsForValue().increment(String.valueOf(count), 1);
            redisTemplate.opsForValue().set(countKey, String.valueOf(count), 10, TimeUnit.MINUTES);
        }
        // 存储返回结果
        Map<String, Object> result = new HashMap<>();
            // 使用工具类生成六位的数字验证码
        String  code = BaseUtil.getRandomCode(aliyunSms.getVerifySize());
            // 将redisTemplate模板对象的key的序列化方式修改为new StringRedisSerializer
            redisTemplate.setKeySerializer(new StringRedisSerializer());
            // 将PhoneNumber当做key,将code当做value存进redis中,时间为10分钟
            redisTemplate.opsForValue().set(aliyunSms.getPhoneNumber(), code, 10, TimeUnit.MINUTES);
            // 获取信息发送成功与否的标志
            boolean flag = this.send(aliyunSms,code);
            // 根据信息是否发送成功,返回不同的内容
            if (flag){
                result.put("message", "验证码发送成功");
            } else {
                result.put("message", "验证码发送失败");
            }
        // 向前端返回信息
        return result;
    }


    /**
     * description : 发送短信验证码-阿里云发送
     *
     */
    public boolean send(AliyunSms aliyunSms,String code) {
        // 连接阿里云
        DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", AccessKeyID, AccessKeySecret);
        IAcsClient client = new DefaultAcsClient(profile);
        // 构建请求
        CommonRequest request = new CommonRequest();
        // 请求方式
        request.setSysMethod(MethodType.POST);
        // 官方需要的和短信请求相关的信息
        request.setSysDomain("dysmsapi.aliyuncs.com");
        request.setSysVersion("2017-05-25");
        request.setSysAction("SendSms");
        // 生成装有短信验证码的map
        Map<String,Object> messageMap = new HashMap<>();
        messageMap.put("code", code);
        // 填写请求参数
        request.putQueryParameter("PhoneNumbers", aliyunSms.getPhoneNumber());
        // 签名名称
        request.putQueryParameter("SignName", aliyunSms.getSignName());
        //模板CODE
        request.putQueryParameter("TemplateCode", aliyunSms.getTemplateCode());
        // 短信模板变量对应的实际值
        request.putQueryParameter("TemplateParam", JSONObject.toJSONString(messageMap));
        try {
            // 发送请求并接受返回值
            CommonResponse response = client.getCommonResponse(request);
            // 把json格式字符串变成Json对象
            JSONObject jsonObject = JSON.parseObject(response.getData());
            // 请求状态码,返回OK代表请求成功,来自官方文档
            String resCode = jsonObject.getString("Code");
            return "OK".equals(resCode);
        } catch (ServerException e) {
            e.printStackTrace();
        } catch (ClientException e) {
            e.printStackTrace();
        }
        return false;
    }
}

3.1 其中实体以及常量类如下:

1.存储用户信息表

@Data
@TableName(value = "XXXXX")
public class SmsLogin {

    /**
     * ID
     */
    @TableId(type = IdType.ASSIGN_ID)
    private String Id;


    /**
     * 手机号码
     */
    private String phoneNumber;

    /**
     * 验证码
     */
    private String verifyCode;

    /**
     * 登录时间
     */
    private String creationTime;


}

2.发送参数实体

@Data
public class AliyunSms {

    /**
     * 签名
     */
    private String signName;

    /**
     * 模板编码
     */
    private String templateCode;

    /**
     * 失效时间
     */
    private Integer timeout;

    /**
     * 验证码长度
     */
    private Integer verifySize;

    /**
     * 手机号码
     */
    private String phoneNumber;

}

3.常量实体

public class AliyunConstant {

    /**
     * 签名
     */
    public static final String ALIYUN_SMS_SIGNNAME = "中科知道";

    /**
     * 长度
     */
    public static final Integer ALIYUN_SMS_VERIFY_SIZE = 6;

    /**
     * 登录
     */
    public static final String ALIYUN_SMS_TEMPLATECODE = "SMS_461560323";


    /**
     * 失效时间
     */
    public static final Integer ALIYUN_SMS_TIMEOUT = 60;
}

第二个接口为校验验证码登录接口

controller

    /**
     * description: 验证码校验-登录
     *
     */
    @PostMapping(value = "/insertCheck", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public Map insertCheck(@RequestBody SmsLogin smsLogin) throws Exception {
        return smsService.insertCheck(smsLogin);
    }



service

    /**
     * description: 验证码校验-登录
     *
     */
    Map insertCheck(SmsLogin smsLogin) throws Exception;


    /**
     * description: 验证码校验-登录
     *
     */
     public Map  insertCheck(SmsLogin smsLogin) throws Exception {
         Map<String, Object> map = new HashMap<>();
         //入参校验
         if (StringUtils.isBlank(smsLogin.getPhoneNumber())|| StringUtils.isBlank(smsLogin.getVerifyCode())) {
             throw new BaseException(1002,"注册失败,缺少必要参数");
         }
         //验证码校验
         // 获取redis中的验证码
         String code = redisTemplate.opsForValue().get(smsLogin.getPhoneNumber());
         if (!StringUtils.isNotNull(code) || !code.equals(smsLogin.getVerifyCode())) {
             throw new BaseException(1003,"验证码错误");
         }
         //数据入库
         SmsLogin sms = new SmsLogin();
         sms.setPhoneNumber(smsLogin.getPhoneNumber());
         sms.setVerifyCode(code);
         sms.setCreationTime(TimeUtil.currentDate());
         try {
             smsLoginMapper.insert(sms);
             map.put("code", 200);
             map.put("message", "您已成功登录");
             map.put("id", sms.getId());
             map.put("phoneNumber", sms.getPhoneNumber());
         } catch (Exception e) {
             throw new BaseException(1004,"登录失败");
         }
         return map;
     }

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

java实现手机号验证码登录功能,并限制同一个IP10分钟以内最多发3次。保姆级教程 的相关文章

随机推荐