springboot框架集合redis 使用jedis实现手机验证功能及超过次数限制登录功能

tech2022-08-05  131

需求分析

用户在客户端输入手机号,点击发送后随机生成4位数字码。有效期为20秒。 输入验证码,点击验证,返回成功或者失败。且每个手机号在1分钟内只能验证3次。并给相应信息提示(并限制2分钟验证) 用户在2分钟内,仅允许输入错误密码5次。 如果超过次数,限制其登录1小时。(要求每登录失败时,都要给相应提式)

思路分析

一、生成验证码方法 随机数方法(生成4位) 二、(生成验证码) 先判断用户后台是否存在验证码(key是否存在) 如果不存在 初始化key 赋值 (生成验证码方法),并设置key过期时间(30秒)

三、校验验证码 将前台输入验证码 和 redis中的验证码进行比较(成功或失败) 成功: 所有的key清除 且每个手机号在2分钟内只能验证3次。并给相应信息提示,如果超过3次。(并限制3分钟验证)如果其点击获取验 证码 给其提示:您已被限制操作,还需多少秒解除限制。

四、防攻击方法 记录IP(每发送验证码 KEY对其进行记录)。设置过期 2分钟。时间。 如果超过了范围,进行限制。 如果超过3次。(并限制3分钟验证)如果其点击获取验 证码 给其提示:您已被限制操作,还需多少秒解除限制。

前端页面

js文件

bootstrap_3.3.7_js_bootstrap.min.js jquery.min.js

index.html

<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="utf-8"> <meta http-equiv="Pragma" content="no-cache"> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/> <meta name="format-detection" content="telephone=yes"/> <meta name="apple-mobile-web-app-capable" content="yes" /> <meta name="apple-mobile-web-app-status-bar-style" content="black" /> <title>绑定信息</title> <!-- Bootstrap core CSS--> <!-- 最新版本的 Bootstrap 核心 CSS 文件 --> <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"> <!-- <script type="text/javascript" th:src="@{/s/jquery.min.js}" src="js/jquery.min.js"></script>--> <style type="text/css"> body{ margin: 0; padding: 0; } .modal_content{ padding: 30px; display: flex; justify-content: center; flex-direction: column; } .modal_content>div{ margin-bottom: 20px; } .modal_content>h5:first-child{ margin:30px 0px; } #dialog label{ color: #666; } #phone1{ display: block; width: 100%; height: 70px; background: none; padding-top: 30px; border: 0; outline:none; text-align: center; margin-top: -30px; font-size: 16px; border-bottom: 1px solid rgba(0,0,0,.2); border-radius: 0; } .code1{ display: flex; flex-direction: row; justify-content: space-between; width: 100%; height: 70px; background: none; padding-top: 30px; margin-top: -30px; font-size: 16px; border-bottom: 1px solid rgba(0,0,0,.2); border-radius: 0; } #code1{ width: calc(100% - 90px); height: 55px; background: none; padding-top: 20px; border: 0; outline:none; text-align: center; margin-top: -20px; font-size: 16px; } #btnSendCode1{ width: 90px; height: 30px; padding: 0 5px; margin: 0; font-size: 14px; text-align: center; background: transparent; border-radius: 30px; color: #a07941; border-color: #a07941; } ::-webkit-input-placeholder { /* WebKit browsers */ font-size: 14px; color: rgba(0,0,0,.4); } :-moz-placeholder { /* Mozilla Firefox 4 to 18 */ font-size: 14px; color: rgba(0,0,0,.4); } ::-moz-placeholder { /* Mozilla Firefox 19+ */ font-size: 14px; color: rgba(0,0,0,.4); } :-ms-input-placeholder { /* Internet Explorer 10+ */ font-size: 14px; color: rgba(0,0,0,.4); } .next{ text-align: center; margin: 20px 0; } .next button{ width: 100%; height: 45px; padding: 0; margin: 0; background: #007BFF; color: #fff; border: 0; outline:none; border-radius: 3px; } </style> </head> <body> <div class="modal_content"> <h5>绑定用户信息!</h5> <div> <label for="phone1">注册手机号:</label><br /> <input id="phone1" type="text" autocomplete="off" value="19965818001" placeholder="请输入已绑定的手机号"/> </div> <div> <label for="code1">验证码:</label> <div class="code1"> <input id="code1" type="text" autocomplete="off" placeholder="短信验证码"/> <input id="btnSendCode1" type="button" class="btn btn-default" value="获取验证码" onClick="sendMessage1()" /> </div> </div> <div class="next"> <button onclick="binding()">确定</button> </div> </div> <script src="http://www.jq22.com/jquery/jquery-1.10.2.js"></script> <script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> <script> var phoneReg = /(^1[3|4|5|7|8|9]\d{9}$)|(^09\d{8}$)/;//手机号正则 var count = 10; //间隔函数,1秒执行 var InterValObj1; //timer变量,控制时间 var curCount1;//当前剩余秒数 /*第一*/ function sendMessage1() { curCount1 = count; var phone = $.trim($('#phone1').val()); if (!phoneReg.test(phone)) { alert(" 请输入有效的手机号码"); return false; } //设置button效果,开始计时 $("#btnSendCode1").attr("disabled", "true"); $("#btnSendCode1").val( + curCount1 + "秒再获取"); InterValObj1 = window.setInterval(SetRemainTime1, 1000); //启动计时器,1秒执行一次 //向后台发送处理数据 $.ajax({ type:"post", url:"[[@{/sendPhoneCode}]]", data:{"phone":phone}, success:function (msg) { alert(msg); } }); } function SetRemainTime1() { if (curCount1 == 0) { window.clearInterval(InterValObj1);//停止计时器 $("#btnSendCode1").removeAttr("disabled");//启用按钮 $("#btnSendCode1").val("重新发送"); } else { curCount1--; $("#btnSendCode1").val( + curCount1 + "秒再获取"); } } /*提交*/ function binding(){ var phone = $("#phone1").val(); var code = $("#code1").val(); //校验 if (code.length<1){ alert("验证码不能为空!!"); } console.log(phone); console.log(code); $.ajax({ type: "post", url: "[[@{/checkCode}]]", data:{"phone":phone,"code":code}, success:function (data) { alert(data); } }); } </script> </body> </html>

controller层

package com.qfzb.controler; import com.qfzb.commons.GenKeyObj; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import javax.servlet.http.HttpServletRequest; @Controller public class UserController { @Autowired private JedisPool jedisPool; /** * 随机生成4位数字验证码的方式 */ public int getPhoneCode(){ int random = (int) (Math.random()*10000); return random; } /** * 发送验证码 * @param phone * @return */ @RequestMapping("/sendPhoneCode") @ResponseBody public String sendPhoneCode(@RequestParam("phone") String phone, HttpServletRequest request){ String key = GenKeyObj.PHONE_REDIS_KEY+phone; //获取连接池 Jedis jedis = jedisPool.getResource(); String result = sendPhoneCode(jedis, request); if (!"null".equals(result)){ return result; } String code = getPhoneCode() +""; if (!jedis.exists(key)){ String set = jedis.set(key,code); System.out.println("set返回值:"+set); //set返回值:OK System.out.println("验证码:"+code+" ,已发送到手机:"+phone); jedis.expire(key,10); } return "验证码已发送到手机"; } /** * 校验验证码 * @return */ @RequestMapping("/checkCode") @ResponseBody public String checkCode(@RequestParam("phone")String phone, @RequestParam("code")String code){ Jedis jedis = jedisPool.getResource(); String key = GenKeyObj.PHONE_REDIS_KEY+phone; String phoneCode = jedis.get(key); //进行校验 if (code.equals(phoneCode)){ //校验成功 清除key jedis.del(key); System.out.println("手机验证成功"); return "手机验证码验证成功"; }else{ return "手机验证码验证失败"; } } /** * 防攻击方法 */ public String sendPhoneCode(Jedis jedis,HttpServletRequest request){ //获取当前操作人的ip地址 String ip = request.getRemoteAddr(); //生成手机验证相关的key String keyIp = GenKeyObj.PHONE_REDIS_KEY+ip; //防攻击判断 Long ipCount = 0L; if (!jedis.exists(keyIp)){ //ip地址不存在,首次初始化,赋值1 ipCount = jedis.incr(keyIp); //设置2分钟过期 jedis.expire(keyIp,120); }else { //非首次获取验证码,如果ipCount==3,则限制登录。如果大于3.则获取限制时间 ipCount = Long.parseLong(jedis.get(keyIp)); //如果ipCount==3 if (ipCount==3){ jedis.incr(keyIp); jedis.expire(keyIp,180);//限制器登录180秒 return "获取验证码次数频繁,限制获取时间"+180+"秒"; } //自增 jedis.incr(keyIp); if(ipCount>3L){ return "获取验证码次数频繁,限制获取时间"+jedis.ttl(keyIp)+"秒"; } } return "null"; } }

接口类:定义controller类中的常量

package com.qfzb.commons; public interface GenKeyObj { String USER_REDIS_KEY="user:"; String GRAND_REDIS_KEY="grand:"; String PHONE_REDIS_KEY="phone:"; }

配置:application.yml文件 连接redis

java: application: name: ch3-redis server: port: 8080 spring: redis: port: 6379 password: 123456 host: 192.168.239.129 jedis: pool: max-idle: 6 max-active: 10 min-idle: 2 lettuce: shutdown-timeout: 2000 database: 0 thymeleaf: cache: false mode: HTML encoding: UTF-8 groovy: template: cache: false
最新回复(0)