转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6134649.html

   另:算术验证码生成的JSP、Servlet实现均已移植github:https://github.com/ygj0930/CheckCode-in-JSP-Servlet

  大家给我个star呀~

在常见的登录功能实现中,单靠账户、密码登录很容易遭受恶意攻击,有些人可以通过写一些脚本自动输入账户密码(当然,是瞎蒙的)频繁登录从而占用服务器的处理资源。这时候,此时,就可以通过验证码来达到拦截“非人类”发出请求。

验证码:全自动区分计算机和人类的图灵测试的缩写,是一种区分用户是计算机的公共全自动程序,这个问题可以由计算机生成并评判,但是必须只有人类才能解答.可以防止恶意破解密码、刷票、论坛灌水、有效防止某个黑客对某一个特定注册用户用特定程序暴力破解方式进行不断的登录。

实现原理:在服务器的servlet中随机生成一个验证码,一般为四位数字、字母,然后把该验证码保存到session作为一个Attribute,然后通过Java的绘图类以图片的形式把该验证码写到浏览器,并设置给Img标签以图片的形式显示出来。最后,在用户提交数据的时候,在服务器端将用户提交的验证码和session中保存的验证码属性值进行比较,并发回验证结果。(如:验证成功则跳转、不成功则发回错误码重新输入)

普通图片验证码

代码实现:

前端:用一个img标签显示验证码图片,一个输入框接收用户输入的验证码。

<script>
function show(o){
//单击图片,重新获得验证码。random的作用是用来修改img图片的来源的,如果没有随机数后缀,则说明没有修改src,浏览器会从缓存中直接读取上一次根据此src获取到的内容进行显示
o.src = "checkCode.jsp?"+Math.random();
}
</script>
<form method="post" action="reg_do.jsp">
请输入验证码:
<input type="text" name="randomCode_Client" />
<br/><br/>
<img src="checkCode.jsp" onclick="show(this)" />
<br/><br/>
</form>

后台:处理登录请求,校对验证码

    //得到客户端传入的验证码参数
String randomCode_client=(String)request.getParameter("randomCode_Client");
//得到session上的验证码
String randomCode_server=(String)session.getAttribute("randomCode"); if(!randomCode_client.equals(randomCode_server)){
//验证码错误做出的响应
}else{
//验证码正确做出的响应
}

后台:生成验证码图片并设置到session中,并把图片输出到浏览器显示

int width = 62, height = 22;//定义验证码图片的大小
BufferedImage buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);//在内存中创建图象
Graphics2D g = buffImg.createGraphics();//为内存中要创建的图像生成画布,用于“作画” //画一个白色矩形,作为验证码背景
g.setColor(Color.WHITE);
g.fillRect(0, 0, width, height);
//画一个黑色矩形边框
g.setColor(Color.BLACK);
g.drawRect(0, 0, width - 1, height - 1); //画40条灰色的随机干扰线
g.setColor(Color.GRAY);
Random random = new Random(); //设置随机种子
for (int i = 0; i < 40; i++) { //设置40条干扰线
int x1 = random.nextInt(width);
int y1 = random.nextInt(height);
int x2 = random.nextInt(10);//返回0到10之间一个随机数
int y2 = random.nextInt(10);
g.drawLine(x1, y1, x1 + x2, y1 + y2);
} //创建字体
Font font = new Font("Times New Roman", Font.PLAIN, 18);
g.setFont(font); int length = 4; //设置默认生成4个长度的验证码
StringBuffer randomCode = new StringBuffer();
for (int i = 0; i < length; i++) { //取得4位数的随机字符串
String strRand = String.valueOf(random.nextInt(10));//返回一个伪随机数,它是取自此随机数生成器序列的、在 0(包括)和指定值(不包括)之间均匀分布的 int 值
int red = random.nextInt(255);
int green = random.nextInt(255);
int blue = random.nextInt(255);
g.setColor(new Color(red, green, blue)); //获得一个随机红蓝绿的配合颜色
g.drawString(strRand, 13 * i + 6, 16);//把该数字用画笔在画布画出,并指定数字的坐标
randomCode.append(strRand);//把该数字加到缓存字符串中。用于等会生成验证码字符串set到session中用于校对
} buffImg.flush();//清除缓冲的图片
g.dispose();//释放资源 session.setAttribute("randomCode", randomCode.toString());//把验证码set为属性 //设置页面不缓存
response.setContentType("image/jpeg");
response.setHeader("Pragma", "no-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0); ServletOutputStream outputStream = response.getOutputStream();
ImageIO.write(buffImg, "jpeg", outputStream);//使用支持jpeg格式的 ImageWriter 将一个图像写入 OutputStream。而在客户端的img标签通过src来从中提取出jpeg图片
outputStream.close(); /*
这两句代码用于解决报错:java.lang.IllegalStateException: getOutputStream() has already been called
由于jsp container在处理完成请求后会调用releasePageContet方法释放所用的PageContext object,
并且同时调用getWriter方法,由于getWriter方法与在jsp页面中使用流相关的getOutputStream方法冲突,
所以会造成这种异常
*/
out.clear();
out = pageContext.pushBody();

更进一步的验证:算术表达式验证。

在上面提到的验证码只不过是一些普通的数字(也可以用字母)图片,用户看着图片的内容输入图片里的数字、字母即可完成验证。其实,这还不算很安全,比如我们可以获取这张图片,通过模式识别等技术解析出图片的内容,那么这样的话图片就起不到拦截“非人类”的作用了。对此,我们可以在单纯的“识别”能力验证上加上一个“逻辑”能力验证——算术验证。

算术验证与普通图片验证不同的地方就在于,取代单纯的数字、字母图片,而采用算术表达式图片作为验证码。用户不仅需要辨析图片,还要在图片的基础上进行简单的算术运算,把运算结果作为验证码。

技术要点:把普通验证码中生成随机数字改为生成随机数字+随机运算符(加减乘除),画成图像发回浏览器显示。为在服务器端,则直接通过算术表达式算出验证码结果,set到session中作为属性以供其他负责验证的jsp文件中用作验证。

实例代码:

int width = 62, height = 22;
BufferedImage buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g = buffImg.createGraphics();
g.setColor(Color.WHITE);
g.fillRect(0, 0, width, height);
g.setColor(Color.BLACK);
g.drawRect(0, 0, width - 1, height - 1);
g.setColor(Color.GRAY);
Random random = new Random();
for (int i = 0; i < 40; i++) {
int x1 = random.nextInt(width);
int y1 = random.nextInt(height);
int x2 = random.nextInt(10);
int y2 = random.nextInt(10);
g.drawLine(x1, y1, x1 + x2, y1 + y2);
}
Font font = new Font("Times New Roman", Font.PLAIN, 18);
g.setFont(font); String[] ops={"+","-","*","/","="};//定义运算符
int num1=random.nextInt(10);//生成第一个操作数
String strRand1 = String.valueOf(num1);
int red1 = random.nextInt(255);
int green1 = random.nextInt(255);
int blue1 = random.nextInt(255);
g.setColor(new Color(red1, green1, blue1)); //画出第一个操作数
g.drawString(strRand1, 13 *0 + 6, 16); int op_num=random.nextInt(4);//随机生成一个运算符数组中的下标,从而得到随机的一个运算符。这里是0~3之间一个随机值。因为4是等号
String strRand2 =(String)ops[op_num];
int red2 = random.nextInt(255);
int green2 = random.nextInt(255);
int blue2 = random.nextInt(255);
g.setColor(new Color(red2, green2, blue2)); //画出操作运算符
g.drawString(strRand2, 13 *1 + 6, 16); int num2=(random.nextInt(9)+1); //随机生成0~8之间的一个数+1,作为第二个操作数。因为有可能出现除法,所以第二个操作数不能为0。所以+1,使数在1~9之间。
String strRand3 = String.valueOf(num2);
int red3 = random.nextInt(255);
int green3 = random.nextInt(255);
int blue3 = random.nextInt(255);
g.setColor(new Color(red3, green3, blue3)); //画出第二个操作数
g.drawString(strRand3, 13 *2 + 6, 16); String strRand4 =(String)ops[4] ;
int red4 = random.nextInt(255);
int green4 = random.nextInt(255);
int blue4 = random.nextInt(255);
g.setColor(new Color(red4, green4, blue4)); //画出等号
g.drawString(strRand4, 13 *3 + 6, 16); Integer randomCode=0; //由运算符的不同执行不同的运算,得到验证码结果值
switch(op_num){
case 0:
randomCode = num1+num2;
break;
case 1:
randomCode = num1-num2;
break;
case 2:
randomCode = num1*num2;
break;
case 3:
randomCode = num1/num2;
break;
}
session.setAttribute("randomCode", randomCode.toString());//把运算符结果值set到session中,用于其他文件进行验证码校对
buffImg.flush();
g.dispose();
response.setContentType("image/jpeg");
response.setHeader("Pragma", "no-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
ServletOutputStream outputStream = response.getOutputStream();
ImageIO.write(buffImg, "jpeg", outputStream);
outputStream.close();
out.clear();
out = pageContext.pushBody();

JavaWeb开发之普通图片验证码生成技术与算术表达式验证码生成技术的更多相关文章

  1. jsp技术和el表达式和jstl技术

    注:本文参考黑马视频的讲义 jsp技术 1.jsp脚本 )<%java代码%> ----- 内部的java代码翻译到service方法的内部 )<%=java变量或表达式> - ...

  2. 动态生成能够局部刷新的验证码【AJAX技术】---看了不懂赔你钱

    在开发JavaWeb应用时,动态生成能够局部刷新的验证码是一项必须的功能,在这里我们将会详细的讲解如何实现这一功能. 一.涉及技术 该功能需要用到AJAX异步传输技术,这样能保证在点击"看不 ...

  3. JavaWeb开发技术基础概念回顾篇

    JavaWeb开发技术基础概念回顾篇 第一章 动态网页开发技术概述 1.JSP技术:JSP是Java Server Page的缩写,指的是基于Java服务器端动态网页. 2.JSP的运行原理:当用户第 ...

  4. [学习笔记]Javaweb开发视频教程之Tomcat9配置

    参考自北京动力节点的视频教程:https://www.bilibili.com/video/av14548279/?p=1 1.Java XE Java SE 是做电脑上运行的软件. Java EE ...

  5. MVC的验证(模型注解和非侵入式脚本的结合使用) .Net中初探Redis .net通过代码发送邮件 Log4net (Log for .net) 使用GDI技术创建ASP.NET验证码 Razor模板引擎 (RazorEngine) .Net程序员应该掌握的正则表达式

    MVC的验证(模型注解和非侵入式脚本的结合使用)   @HtmlHrlper方式创建的标签,会自动生成一些属性,其中一些属性就是关于验证 如图示例: 模型注解 通过模型注解后,MVC的验证,包括前台客 ...

  6. 李兴华JavaWeb开发笔记

    李兴华JavaWeb开发笔记 1.Java语法-基础 环境变量-JAVA_HOME, PATH, ClassPath 变量名 作用 举例 JAVA_HOME 指向JDK目录 C:\Program Fi ...

  7. JavaWeb开发环境配置

    JavaWeb开发环境配置(win7_64bit) 目录 1.概述 2.JavaWeb学习路线 3.JavaWeb常用开发环境搭建 4.注意事项 >>看不清的图片可在新标签打开查看大图 1 ...

  8. 详细阐述Web开发中的图片上传问题

    Web开发中,图片上传是一种极其常见的功能.但是呢,每次做上传,都花费了不少时间. 一个"小功能"花费我这么多时间,真心不愉快. So,要得认真分析下原因. 1.在最初学习Java ...

  9. JavaWeb学习总结-01 JavaWeb开发入门

    一 基本概念 1 Web开发的相关知识 Web,表示网页的意思,它用于表示Internet主机上供外界访问的资源. Internet上供外界访问的Web资源分为: 静态web资源(如html 页面): ...

随机推荐

  1. 暴君第一季/全集Tyrant迅雷下载

    本季第一季 Tyrant Season 1 (2014)看点:虽然李安退出了FX系列剧<暴君>(Tyrant),称不想耽误了剧集的制作,但显然FX对这部剧的重视程度非比寻常,因为他们找来的 ...

  2. Android Activity启动流程源码全解析(2)

    接上之前的分析 ++Android Activity启动流程源码全解析(1)++ 1.正在运行的Activity调用startPausingLocked 一个一个分析,先来看看startPausing ...

  3. 深入理解Java并发之synchronized实现原理

    深入理解Java类型信息(Class对象)与反射机制 深入理解Java枚举类型(enum) 深入理解Java注解类型(@Annotation) 深入理解Java类加载器(ClassLoader) 深入 ...

  4. 彻底理解Java的feature模式

    先上一个场景:假如你突然想做饭,但是没有厨具,也没有食材.网上购买厨具比较方便,食材去超市买更放心. 实现分析:在快递员送厨具的期间,我们肯定不会闲着,可以去超市买食材.所以,在主线程里面另起一个子线 ...

  5. [转]Linux awk 命令 说明

    From : http://blog.csdn.net/tianlesoftware/article/details/6278273 一.  AWK 说明 awk是一种编程语言,用于在linux/un ...

  6. SpringBoot整合Quartz定时任务 系统job Spring Boot教程 调度任务

    原文地址:https://www.cnblogs.com/allalongx/p/8477368.html 构建工程 创建一个Springboot工程,在它的程序入口加上@EnableScheduli ...

  7. js转义和反转义html htmlencode htmldecode

    文章目录 JS实现HTML标签转义及反转义 用Javascript进行HTML转义 1.HTML转义 2.反转义 3.一个有意思的认识 4.完整版本的代码 其他 [转义字符]HTML 字符实体< ...

  8. RateLimiter

    RateLimiter是Guava的concurrent包下的一个用于限制访问频率的类. 限流算法 常用的更平滑的限流算法有两种:漏桶算法和令牌桶算法. 很多传统的服务提供商如华为中兴都有类似的专利, ...

  9. 数据库实例: STOREBOOK > 用户 > 编辑 用户: SYS

    ylbtech-Oracle:数据库实例: 数据库实例: STOREBOOK  >  用户  >  编辑 用户: SYS 编辑 用户: SYS 1. 一般信息返回顶部 1.1, 1.2, ...

  10. 在Win7 Hyper-v虚拟机中挂接真实机的声卡

    最近在测试Lync的语音功能,环境已在虚拟机中搭建好,但Hyper-V中不支持声卡,一直未测试成功,经过一番尝试后终于成功,细节如下: 1.真机为Win7 企业版,虚拟机也是Win7的企业版.(虚拟机 ...