近期对登录注册与获取短信验证码的接口做了安全限制,其中一部分就用到了谷歌的captcha验证码,比如当用户连续三次登陆失败,那么之后的登录请求就需要用户输入谷歌的图形验证码。由于web端和app端调用的都是同一个获取谷歌验证码的接口,所以后端这个生成图片验证码的接口就与传统的直接将验证码图片写入到前端的方式不同,此时接口返回的应该这个经过base64编码后的验证码图片二进制流,然后由前端自行解析(web和app解析这个图片流的方式有些不一样)显示出来。主要代码可以借鉴这篇https://blog.51cto.com/4925054/2103196,下面分享我借鉴完后,自己做的一些修改。

首先是依赖的jar:

     <!-- 谷歌验证码 --><dependency><groupId>com.github.penggle</groupId><artifactId>kaptcha</artifactId><version>2.3.2</version></dependency>

然后将生成验证码的com.google.code.kaptcha.impl.DefaultKaptcha类交给spring进行管理,在spring-mvc.xml文件中的配置是:

 <!-- 谷歌验证码 --><bean id="captchaProducer" class="com.google.code.kaptcha.impl.DefaultKaptcha"><property name="config"><bean class="com.google.code.kaptcha.util.Config"><constructor-arg><props><prop key="kaptcha.border">yes</prop><prop key="kaptcha.border.color">105,179,90</prop><prop key="kaptcha.textproducer.font.color">blue</prop><prop key="kaptcha.image.width">200</prop><prop key="kaptcha.image.height">80</prop><prop key="kaptcha.textproducer.font.size">70</prop><prop key="kaptcha.session.key">code</prop><prop key="kaptcha.textproducer.char.length">4</prop><prop key="kaptcha.textproducer.font.names">宋体,楷体,微软雅黑</prop></props></constructor-arg></bean></property></bean>

具体的参数配置可以参考这篇博客:https://714501466.iteye.com/blog/1308756 ,我也是直接拿人家的来用的!!!

接下来就是大家最喜欢的controller层的接口了:

package demo;import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.util.Map;import javax.imageio.ImageIO;
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.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;import com.google.code.kaptcha.Producer;import sun.misc.BASE64Encoder;
import sy.util.redis.RedisUtils;/*** @author hqq* */@Controller
@RequestMapping("/demo")
public class RegAndLoginController {private static final Logger logger = Logger.getLogger(RegAndLoginController.class);@Autowiredprivate Producer captchaProducer;/*** 获取谷歌验证码* * @param request* @param response* @throws Exception*/@RequestMapping(value = "/captcha")@ResponseBodypublic Result getKaptchaImage(@RequestParam("mobile") String mobile, @RequestParam("type") String type,HttpServletRequest request) {Result result = new Result();if (StringUtils.isBlank(mobile) || StringUtils.isBlank(type)) {result.setSuccess(false);result.setMsg("非法请求,不予处理");return result;}//由于该接口是没有做权限校验的,任何人不登录都可以随意调用,所以此处建议做个每日访问次数的限制String ip = IpUtil.getIpAddr(request);String visitKey = ip +"_captcha_"+mobile;String visitCount = RedisUtils.get(visitKey);int count = 1;if (visitCount != null) {count = new Integer(visitCount);if (count >= 100) {result.setSuccess(true);result.setMsg("您今日调用此接口次数已达上限");return result;}count++;}RedisUtils.set(visitKey, count+"", DateUtils.getSurplusTime());if(!",login,register,".contains(","+type+",")){result.setSuccess(false);result.setMsg("非法请求,传入的参数错误");return result;       }// 生成验证码String capText = captchaProducer.createText();String key=type+"_captcha_"+mobile;//当前验证码的时间可以设置的稍长些,防止用户在登录界面停留太长时间导致验证码失效了RedisUtils.set(key, capText.toLowerCase(), 60 * 30);//半个小时// 向客户端写出try {BufferedImage bi = captchaProducer.createImage(capText);// 生成图片验证码ByteArrayOutputStream outputStream = new ByteArrayOutputStream();ImageIO.write(bi, "jpg", outputStream);//高能预警!!!// 对字节数组Base64编码BASE64Encoder encoder = new BASE64Encoder();String img = encoder.encode(outputStream.toByteArray());result.setSuccess(true);result.setMsg("验证码生成成功");result.setImg(img);//返回图片的路径} catch (Exception e) {result.setSuccess(false);result.setMsg("系统异常:" + e.getMessage());}return result;}}

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

工具类IpUtil.java如下:

package util;import java.net.InetAddress;import javax.servlet.http.HttpServletRequest;public class IpUtil {/*** 获取请求的客户端的ip地址* * @param request* @return*/public static String getIpAddr(HttpServletRequest request) {String ipAddress = request.getHeader("x-forwarded-for");if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {ipAddress = request.getHeader("Proxy-Client-IP");}if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {ipAddress = request.getHeader("WL-Proxy-Client-IP");}if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {ipAddress = request.getRemoteAddr();if (ipAddress.equals("127.0.0.1") || ipAddress.equals("0:0:0:0:0:0:0:1")) {// 根据网卡取本机配置的IPInetAddress inet = null;try {inet = InetAddress.getLocalHost();ipAddress = inet.getHostAddress();} catch (Exception e) {e.printStackTrace();}}}// 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割if (ipAddress != null && ipAddress.length() > 15 && ipAddress.indexOf(",") > 0 ) { // "***.***.***.***".length()ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));}return ipAddress;}}

web前端的js代码如下:

 //获取图形验证码function getCodeImg(num,mobile) {$.ajax({type:"post",url:root+"/demo/captcha.action",async : false,data:{id:id,type:1},error:function(err){},success:function(r){if(r.success){$("#codeImg").attr('src','data:image/jpeg;base64,'+r.img+'');}else{pophint(r.msg)}}})}

效果如下:

app端的调用也是发ajax请求,具体代码我没有,反正是成功显示了,另外附上一篇博客,ios开发可以试试从这里找找:https://blog.csdn.net/sjl_leaf/article/details/48179299

为了防止该博文失效,截取一部分核心内容:

这是他的核心代码,安全起见,此处备份一下:

//参数在这里 + (void) setImageView:(UIImageView *)imageView WithString:(NSString *)avatar
//二进制显示/*服务器返回:例如data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAIAAACRXR/mAAAABnRSTlMAAAAAAABupgeRAAAAhElEQVRYhe3Y0QmAIBhF4YwGaZRGaNRGaJRGaYEyTj/RfTjnVYQPBRXbuh9DXuPfgOtkkWSRZJFkkUJZU3H+tsx3Q5VrLXS1ZJFkkWSRZJFkkWSRZJFkkUJZLfPH5vktX3mtv54buomySLJIskihrNBTvvWHP0V37oDQTZRFkkWSRQplnQDfEjVVBe3tAAAAAElFTkSuQmCC*/NSArray *imageArray = [avatar componentsSeparatedByString:@","];NSData *imageData = [[NSData alloc] initWithBase64EncodedString:imageArray[1] options:NSDataBase64DecodingIgnoreUnknownCharacters];imageView.image = [UIImage imageWithData:imageData];

至此,分享结束,希望能帮到各位!验证码的话,话说腾讯出的防水墙功能好像很牛的样子,大家感受一下:https://007.qq.com/online.html

springmvc使用谷歌captcha生成图片验证码,并将验证码图片以二进制流的方式返回给前端(app和pc端都能调用)相关推荐

  1. SpringMVC 上传文件或图片并以二进制流的方式存到数据库

    最近些项目遇到一个上传图片和文件并且以二进制流的方式存到数据库,下面介绍一个小案例: 所需jar包: commons-fileupload-1.2.1.jar jsp页面: 后端代码: 值得注意的是: ...

  2. 如何将图片验证码转换为文字,图片识别。

    先在快识免费验证码识别上 http://fast.net885.com/ 注册一个账号,可以免费试用,注册无限制. 每日送1000免费额度. 然后调用其中API,免费识别,准确率高,方便简单. 2.识 ...

  3. [Hei.Captcha] Asp.Net Core 跨平台验证码实现

     写在前面 说起来比较丢脸.我们有个手机的验证码发送逻辑需要使用验证码,这块本来项目里面就有验证码绘制逻辑,.Net Framework的,使用的包是System.Drawing,我把这验证码绘制 ...

  4. DVWA11_Insecure CAPTCHA(不安全的验证码)

    漏洞原理 漏洞防御 环境搭建 Low Medium High 漏洞原理 CAPTCHA:Completely Automated Public Turing Test to Tell Computer ...

  5. Spring Boot 配置Kaptcha(谷歌验证码工具)(生成验证码、验证验证码)

    1 Kaptcha 1.1 Kaptcha简介 Kaptcha 是一个扩展自simplecaptcha的验证码库,默认情况下,Kaptcha非常易于设置和使用,并且默认输出会产生一个很难验证的验证码. ...

  6. python爬虫遇到验证码、输入验证码后提醒验证码错误_爬虫遇到头疼的验证码?Python实战讲解弹窗处理和验证码识别...

    前言 在我们写爬虫的过程中,目标网站常见的干扰手段就是设置验证码等,本就将基于Selenium实战讲解如何处理弹窗和验证码,爬取的目标网站为某仪器预约平台 可以看到登录所需的验证码构成比较简单,是彩色 ...

  7. 图形验证码+短信验证码【Java应用实例】

    一.图形验证码的实现 1.1 简介 常在网上晃悠的人,对下面这张图都不会陌生.特别是在注册新账号.确认交易时,它们都会频繁出现,要求我们输入正确的验证码,那这些看上去跟我们要做的事情完全无关的验证码到 ...

  8. Vue+Spring Boot实现图片验证码、邮箱验证码以及Cookie记住我功能(前后端代码详解)

    Vue实现图片验证码.邮箱验证码以及Cookie记住我功能 前言 图片验证码实现 Vue前端实现 Spring Boot后端实现 邮箱验证码实现 Vue前端实现 Spring Boot后端实现 Coo ...

  9. 短信验证码、图形验证码、邮件验证的自动化测试

    短信验证码.图形验证码.邮件验证问题在自动化测试中是一个很常见的问题,也是一个很棘手的问题.设计的初衷其实就是为了防自动化,防止一些人利用自动工具恶意攻击网站,而很不幸的是,我们所使用的一些自动化测试 ...

最新文章

  1. 毕业后的五年拉开大家差距的原因在哪里
  2. 04:网络层协议介绍
  3. 观点 | 云原生时代来袭 下一代云数据库技术将走向何方?
  4. Linux系统检测命令有哪些
  5. shell编程--基本格式,基本语法,运算符,expr,(()),$[]
  6. mysql 各表charset不同_MySQL表字段字符集不同导致的索引失效问题
  7. UVA 1156 - Pixel Shuffle(模拟+置换)
  8. onpagefinished等了很久才执行_今天自律了吗?停课不停锻炼 才是战疫正确姿势
  9. 【剑指Offer学习】【面试题66:矩阵中的路径】
  10. 这些面试题你需要知道
  11. jQuery实现瀑布流
  12. 008/160 CrackMe Andrénalin #1
  13. oracle中一个月的最后一天,SQL和Oracle获取每周、每月、每年第一天和最后一天
  14. python构造自定义数据包_Python发送网络封包,自定义封包结构与内容并发出去
  15. 网站上线前期应该如何制定关键词优化策略
  16. STM32--ADC
  17. 功能自动化测试的策略有哪些?
  18. opengl 画椭圆_椭圆围城与圆型观光步道
  19. c++镇国之争游戏(带存档,无bug)
  20. 微信开发 注意 js接口安全域名 invail url domain

热门文章

  1. C# MethodInvoker委托的使用
  2. Linux配置scheme环境,vim配置文件 + colorscheme koehler设置窗口颜色
  3. ffmpeg 将拆分的数据合成一帧_FFmpeg 简单合成 MP4 :视频解封与重新封装
  4. 输入任意一种物质,要求输出其每种元素的数量。比如输入 CaCO3,其组成分别为 Ca:1,C:1,O:3,输出 Ca1C1O3
  5. 知道等级保护测评都有哪些工作内容吗?
  6. 测试软件响应时间需求,性能测试知多少---性能需求分析
  7. [go学习笔记.第十一章.项目案例] 2.客户信息管理系统
  8. JS无缝轮播图(支持点击左右切换,小圆点切换,定时器自动播放)
  9. 自回归滑动平均模型ARMA
  10. Android Drawable缓存