项目原来使用的短信验证码接口没有做安全限制,去网上查找了很多的解决方案,无非是在接口调用时添加图形验证码、单ip请求限制、限定每天每个号码获取短信验证码的次数、限制短信验证码的调用频率等。逛了一大圈,发现大家都只是信心满满的分享着一大堆逻辑和方法,至于具体的代码实现,就。。。大概大神们都觉得这东西没有什么技术含量吧。但是我觉得,所有的技术无论高低,业务不管复杂简单,都应该得到尊重,都有被分享的意义。因为在未来漫长的岁月中,总有人会因为这次的分享而得到帮助,哪怕只有一点点。刚好借着这次机会,分享本人一时性起写出的demo(只有逻辑哦,核心业务用你自己的就好),希望此贴之后,越来越多更牛逼的和更完善的demo能被各路高手实现和分享出来,也不枉我辈青年才俊将最美好的十年给了 IT 这一行!

下面请看业务层的代码:

package demo;import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import com.alibaba.fastjson.JSON;/*** @author hqq* */
@Service("mobileService")
public class MobileServiceImpl implements MobileService {private static final Logger logger = Logger.getLogger(MobileServiceImpl.class);@Overridepublic Result findCode(String mobile, String type, String imgCode, HttpServletRequest request) {//mobile字段是传入的用户名,即手机号,必传字段;//type是传入的需要发送的短信类型,必传字段,如登录,注册等(也可以不区分,按个人爱好喽);//imgCode是传入的图形验证码,非必传字段,因为只有今日第四次调用该接口时才需要校验图形验证码Result result = new Result();//校验请求参数是否正确if (StringUtils.isBlank(mobile) || StringUtils.isBlank(type)) {result.setSuccess(false);result.setMsg("请求参数不全");return result;}mobile = mobile.trim();// 判断传入的手机号格式是否正确if (mobile.length() != 11 || !MobileUtil.isMobileNum(mobile)) {result.setSuccess(false);result.setMsg("手机号格式不正确");return result;}// 要发送的短信验证码,生成六位数字验证码String mobileCode = (int) ((Math.random() * 9 + 1) * 100000) + "";String modelCode = null;//我这里使用的是阿里云的短信服务,//调用阿里云的短信接口需要传入一个模板code参数,//这个code再你申请短信模板时就会产生,且固定的值//判断当前要发送的是哪种类型的短信,不同的类型的验证码应该进行区分,这样可以提高//用户体验;区分的参数由调用者(前端开发人员)传入,通常不会出现参数不存在的问题switch (type) {case "register":// 发送注册的短信验证码//核心业务隐身符1,用手机号去自己数据库查询当前用户是否存在,//如果存在,则不能发送该类手机验证码,提示用户直接登录if(手机号已注册){//伪代码result.setSuccess(false);result.setMsg("当前手机号已注册,请直接登录");return result;}modelCode = "SMS_123456788";break;case "reset":// 发送重置登录密码的短信验证码//核心业务隐身符1,用手机号去自己数据库查询当前用户是否存在,//如果不存在,则不能发送该类手机验证码,提示用户注册if(手机号未注册){//伪代码result.setSuccess(false);result.setMsg("当前手机号未注册,请先注册");return result;}modelCode = "SMS_987654321";break;default:result.setSuccess(false);result.setMsg("非法请求");return result;}String mobileKey = type+"_mobile_" + mobile;String todayKey = "today_mobile_code_times_" + mobile;// 验证码三十分钟内有效,并且距离上一次发送要超过2分钟的时间才能重新发送Long times = RedisUtils.ttl(mobileKey);if (times > 60 * 28) {result.setSuccess(false);result.setMsg("距离您上次发送验证码不足两分钟,请两分钟后再尝试获取");return result;}// 判断当前手机号今天发送密码次数是否已达上线,每天15条(具体条数根据自己的需求调用)String todayTimes = RedisUtils.get(todayKey);int todayCount = 1;if (todayTimes != null) {todayCount = new Integer(todayTimes);if (todayCount >= 15) {//此时还可以记录当前用户的手机号,ip,调用的短信验证码类型到表中,//方便系统记录与分析。系统可以分析该用户该周该月调用短信接口的次数//由此来分析该ip的用户是否是正常的用户,如果调用太频繁,//比如连续一周或数周都在调用该接口,系统可以暂时禁用该ip发来的请求,//或者降低该手机号获取短信验证码的次数一般大网站通常都得使用大数据来监控了,//而小网站,就没必要整的这么复杂了result.setSuccess(false);result.setMsg("当前手机号今日发送验证码已达上限,请明日再来");return result;}todayCount++;}//今天发送短信超过三次,再次调用接口时,需要调谷歌图形验证码if(todayCount>3){result.setStatus(1);//只要今日获取验证码次数超过三次,//之后每次获取都要谷歌验证码,这个标识返回给前端,//前端看到这个值,需要调用谷歌图形验证码,//待用户输入图形验证码后才能调用该接口if(StringUtils.isBlank(imgCode)){result.setSuccess(false);result.setMsg("为保证您账号安全,本次请求需要输入图形验证码");return result;}// 检验图形验证码String kapchatKey =type+ "_kaptcha_" + mobile;String kapchat = RedisUtils.get(kapchatKey);//获取redis数据库保存的谷歌图形验证码if (kapchat == null) {result.setMsg("图形验证码已失效,请重新输入");result.setSuccess(false);return result;} else if (!kapchat.equals(imgCode.toLowerCase())) {result.setSuccess(false);result.setMsg("您输入的验证码错误,请重新输入");return result;}}else if(todayCount==3){result.setStatus(1);//这已是第三次调用,下次调用时,就得传入谷歌验证码}String msg = "";//发送短信验证码是否成功与失败try {//发送短信验证码,请求成功后返回指定标识,请求失败,可以返回失败的信息,//方便开发人员排查bug。此处使用的是阿里云的短信服务,//你也可以使用其他的短信服务,此处不做赘述msg = MobileCodeUtils.sendCode(mobile, modelCode, mobileCode);logger.info("手机号:" + mobile + " 的验证码是:" + mobileCode);if (msg != null && "SUCCESS".equals(msg)) {result.setSuccess(true);result.setMsg("您的手机验证码发送成功,请注意查收,本验证码30分钟内有效");// 保存验证码到redisRedisUtils.set(mobileKey, mobileCode, 60 * 30 + 5);//redis中的code比实际要多5秒// 记录本号码发送验证码次数RedisUtils.set(todayKey, todayCount + "", MobileUtil.getSurplusTime());// 删除图形验证码RedisUtils.del(kapchatKey);} else {result.setSuccess(false);result.setMsg("短信验证码发送失败:" + msg);return result;}} catch (Exception e) {result.setSuccess(false);result.setMsg("获取短信验证码异常:" + e.getMessage());logger.info("获取手机验证码异常:" + e.getMessage());return result;}//此处需要添加操作流水,记录哪个手机号,哪个ip,哪个时间调用了哪种类型的接口return result;}
}

获取谷歌kaptcha图形验证码的方式请看我的上一篇博客:https://blog.csdn.net/weixin_42023666/article/details/89561592

RedisUtils.java工具类请看我的另一篇博客:https://blog.csdn.net/weixin_42023666/article/details/89287418

MobileCodeUtils.java是封装好的调用第三方短信验证码的工具类,此时我使用的是阿里云的短信服务,各位只需将自己项目原来的短信工具类进行修改,只要能保证发送短信的功能就可以了。具体的不赘述,毕竟不是本帖的重点,阿里云短信服务的接入可以参考这篇博文:https://blog.csdn.net/weixin_42023666/article/details/101770229 ,也可自行百度。

然后是MobileUtil.java类:

package mobile;import java.util.regex.Pattern;
import java.util.Calendar;
import java.util.Date;import org.apache.commons.lang.StringUtils;/*** @ClassName: MobileUtil  * @author hqq  */
public class MobileUtil {/*** 正则表达式:验证手机号*/private static final String REGEX_MOBILE = "^((13[0-9])|(15[^4,\\D])|(18[0-3,5-9])|(17[0-9]))\\d{8}$";/*** 判断是否是手机号格式,如果传入的是空串,返回false* @param mobile* @return 校验通过返回true,否则返回false*/public static boolean isMobileNum(String mobile) {if(StringUtils.isBlank(mobile)){return false;} return Pattern.matches(REGEX_MOBILE, mobile);}/*** 获取今日的剩余时间,返回值单位:秒* @return*/public static Integer getSurplusTime(){Calendar c = Calendar.getInstance();long now = c.getTimeInMillis();c.add(Calendar.DAY_OF_MONTH, 1);c.set(Calendar.HOUR_OF_DAY, 0);c.set(Calendar.MINUTE, 0);c.set(Calendar.SECOND, 0);c.set(Calendar.MILLISECOND, 0);long millis = c.getTimeInMillis() - now+2000;return (int)(millis/1000);}}

至此,本帖分享结束。

Java后端防止获取短信验证码接口被恶意调用的代码实现相关推荐

  1. thinkphp+小程序手机短信验证码(防止恶意调用短信接口)

    thinkphp+小程序手机短信验证码 前言 一.短信轰炸是什么? 二.小程序准备 1.wxml 2.wxss 3.js(使用小程序定时器限制) 三.后台接口(ThinkPHP) 前言 一.短信轰炸是 ...

  2. 防止短信验证码接口被频繁调用

    加图形验证码 步骤1.利用session2.前端显示后台返回的图形验证码图片3.用户在短信快捷登录的时候,先将手机号+图形验证码请求后台,后台验证成功后,发送验证码

  3. Jmeter获取短信验证码接口压测

    主要学习的内容包括发送HTTP请求.HTTP信息头管理器.HTTP cookies管理器.用户定义的变量.响应断言.CSV数据文件设置的使用. 一.测试相关网站及接口说明: 提供的测试网址为:http ...

  4. Jmeter-函数助手-随机函数的使用(模拟1000+个手机用户获取短信验证码)

    如何模拟1000个手机用户登录? 现在很多APP或者网站都需要使用手机号进行登录,那么使用手机号进行登录时,必然就需要"手机号+短信验证码"才可登录成功. 在实际测试过程中,测试人 ...

  5. java微信公众号短信验证码_解决微信端公众号网页获取短信验证码ajax重复调用两次的问题...

    问题背景介绍: 微信公众号网页开发的时候,点击发送短信验证码,如果响应时间超长,目前测试是10秒左右(这个10秒左右,是我自己多次测试总结出来的规律) 超过10秒左右,就会自动请求第二遍,这个问题挺恶 ...

  6. java叮咚云短信验证码接口调用

    最近在写后台,所以有些方法想记录下来,下面是叮咚云短信验证码接口调用,叮咚云的地址http://www.dingdongcloud.com/,里面有详细的信息,下面是我写的一个方法,仅供参考. imp ...

  7. java防止注册刷短信攻击_java面试(1)如何防止恶意攻击短信验证码接口

    防止恶意攻击短信验证码接口方法 1.手机号码限制:限制单个手机号码每天的最大发送次数.超过次数不能发送短信,可以考虑将手机号码加入黑名单,禁止1天. 2.短信发送时间间隔限制:限制同一个手机号码重复发 ...

  8. 容联云通讯php短信接口,开发中使用 【容联 云通信】获取短信验证码的 Javascript 接口...

    开发中使用 [容联 云通信]获取短信验证码的 Javascript 接口 在平台应用列表添加应用. 在测试号码中绑定测试手机号码,只有这个号码能接收验证短信. 在项目中绑定配置:将控制台首页的开发者主 ...

  9. java获取短信验证码_Java如何获取短信验证码

    [基于创蓝253云通讯平台---短信验证码接口调用demo] package com.bcloud.msg.http; import java.io.ByteArrayOutputStream; im ...

  10. 全国通用标准化HTTP短信验证码接口,接入从未如此简单

    熟练掌握接口对接是一个程序猿的基本功,短信验证码接口作为企业商用最常见也是用的最多的一个接口,能够快速的接入当然是可以省下不少的时间啦!下面给大家介绍一个简单快速的接入方法啦! 验证码的前端代码很简单 ...

最新文章

  1. linux c 线程的创建、线程等待、线程终止、线程分离
  2. cnn handwrite使用原生的TensorFlow进行预测
  3. python代码雨代码复制_python实现跨excel sheet复制代码实例
  4. Google Mock启蒙篇 [2] (Google C++ Mocking Framework for Dummies 翻译)
  5. 三维重建:三维空间中平面的旋转公式
  6. 消息队列 Kafka 的基本知识及 .NET Core 客户端
  7. matlab优化设计例程,优化设计Matlab_实例解析
  8. 小布老师Oracle 9i DBA Fundamentals I视频讲座
  9. printf 输出格式、域宽
  10. FreeSSL + ACME自动化续期域名SSL证书(支持泛域名)
  11. 领域对象映射到微服务代码模型
  12. 网站做SEO优化的5个理由
  13. 【简单快捷教会你】如何正确使用animate.css,各种动态效果。
  14. docker 部署 gitlab gitlab-runner 实现 CI
  15. 短信验证注册,一个完整而优雅的JAVA后端实现
  16. 看完这篇文章你就可以告诉领导你精通Zookeeper了
  17. WinCC在C脚本创建电子签名对话框
  18. 使用google map v3 api 开发地图服务
  19. JS移动客户端--触屏滑动事件
  20. 配置路由器IP及测试连通性

热门文章

  1. 医宗金鉴自学指南_自学中医看什么书
  2. 每个国家对应的语言Locale和国家代码对照表(国际化支持)
  3. 红外接收hs0038NEC协议
  4. 文件太多,台式电脑迁移数据到笔记本怎么操作?
  5. 获取网站url ico小图标
  6. mfc获取计算机的连接端口,[求助]请问socket编程里,服务器端用什么函数获取客户端的地址与端口...
  7. 人脸关键点检测论文总结
  8. python里面pop代码什么意思_python里的pop是什么
  9. UWB定位系统在冬奥会上满足哪些需求
  10. 2021夏令营全记录·华科计算机、中科院网络中心、中科院软件所、浙软