转载请注明原文地址: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. 清道夫第一季/全集Ray Donovan迅雷下载

    清道夫 第一季 Ray Donovan Season 1 (2013)本季看点:Ray Donovan.一位专职于为洛杉矶的名人和富豪服务的神秘人士.他可以巧妙的解决这个城市中富豪们的那些最麻烦同时又 ...

  2. Android之仿String的对象驻留

    String a = "abc"; String b = "abc"; a == b     true; 变量a和变量b是同一个值.这不只是说它俩的值是一样的, ...

  3. 选中TreeView的某节点,并加背景颜色

    一:按钮事件,遍历所有节点 private void button2_Click(object sender, EventArgs e) { foreach (TreeNode n in TreeVi ...

  4. Asp.Net Core 文件上传处理

    本文主要介绍后台接收处理 1.在使用控制器接收 : [HttpPost] : public IActionResult UploadFiles(IList<IFormFile> files ...

  5. [转]Apache 配置虚拟主机三种方式

    转自: http://www.cnblogs.com/hi-bazinga/archive/2012/04/23/2466605.html 一.基于IP 1. 假设服务器有个IP地址为192.168. ...

  6. vim的翻页、跳转到某一行功能

    第一种方式 :$ 跳转到最后一行 :1 跳转到第一行 :n 跳转到第n行 第二种方式 shift+g 跳转到最后一行 gg 跳转到第一行 command+上下箭头

  7. python Genarator函数

    Generator函数的定义与普通函数的定义没有什么区别,只是在函数体内使用yield生成数据项即可.Generator函数可以被for循环遍历,而且可以通过next()方法获得yield生成的 数据 ...

  8. Latex使用的注意事项

    CTEX : CTeXDownload latex中的图片格式主要就2种 pdf 和 eps.如果要用pdflatex编译,那么自然选择pdf,如果用latex编译,自然用eps.本人论文中的图片来源 ...

  9. 构建配置 ProGuard Shrink 混淆和压缩

    官方文档 压缩代码和资源 要尽可能减小 APK 文件,您应该启用压缩来移除 release build 中未使用的代码和资源.此页面介绍如何执行该操作,以及如何指定要在构建时保留或舍弃的代码和资源. ...

  10. 热修复 DexPosed AOP Xposed MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...