相信大家对验证码这玩意不会陌生,无论是申请账号还是某些情况下登录时都会要求输入验证码。经过统计,验证码一次验证就成功通过的概率是90%,并不高,那么很多人对于这种降低用户体验度的设计肯定会怀疑他的必要性,但黑格尔说过:凡是合乎理性的东西都是现实的;凡是现实的东西都是合乎理性的。接下来我们来了解一下验证码。
验证码是一种区别用户是计算机还是人的公共全自动程序,他被用于防止恶意破解密码、刷票、论坛灌水,防止黑客通过暴力破解方式不断地登录,应用于银行、社区、论坛、投票系统等等。
废话不多说我们来看看我已知的用Java实现验证码的四种方式。
方法一:
第一种方法是我最先想到的,也是实现逻辑最简单的,但效率、安全性极其不高。
具体操作就是:1、用photoshop制作出验证码图片,矩形图片上可有必要的英文字母、数字或中文(如上)
2、将图片显示在swing控件中或是jsp页面中
3、在代码中为每张图片匹配上相应的验证码字符串
4、在提交时获取组件或文本框中的字符串与每张图片的字符串用equals()方法进行比较
缺憾就是制作验证码图片的过程太费时,实现方法极low,极不推荐这样实现,下面的方法将越来越高效美观相对安全。
方法二:
这里讲Java Web,Servlet下的验证码实现,实现起来逻辑还是很清晰的。
省去较简单的实现代码,我们先从前台关键代码说起:
当我们点击"看不清"时,验证码图片会进行一个刷新,会调用一个js函数用于重新设置图片路径来更换图片,请看下面代码,代码中<%=request.getContextPath()%>是为了解决相对路径的问题,可返回站点的根路径,而/servlet/ImageServlet是一个整体,指向的就是ImageServlet这个servlet,为什么要在之前加个/servlet呢,因为我们在web.xml中做了配置映射,可理解为换了个更长的名称。接着看下面js函数,可能有些人会有疑问,为什么获取一个当前时间然后加在路径最后呢,其实这是为了解决浏览器缓存的问题,就是当触发了ImageServlet后虽然验证码图片换了但缓存还没变显示出来的验证码图片不变的问题,借助每时每刻时间不同可以让浏览器缓存失效。
1 <script type="text/javascript"> 2 function reloadCode(){ 3 var time = new Date().getTime(); 4 document.getElementById("imagecode").src="<%=request.getContextPath() %>/servlet/ImageServlet?d="+time; 5 } 6 </script>
js函数
下面是web.xml中的关键配置信息:
1 <servlet> 2 <servlet-name>ImageServlet</servlet-name> 3 <servlet-class>com.muke.ImageServlet</servlet-class> 4 </servlet> 5 <servlet> 6 <servlet-name>LoginServlet</servlet-name> 7 <servlet-class>com.muke.LoginServlet</servlet-class> 8 </servlet> 9 <servlet-mapping> 10 <servlet-name>ImageServlet</servlet-name> 11 <url-pattern>/servlet/ImageServlet</url-pattern> 12 </servlet-mapping> 13 <servlet-mapping> 14 <servlet-name>LoginServlet</servlet-name> 15 <url-pattern>/servlet/LoginServlet</url-pattern> 16 </servlet-mapping>
web.xml
然后我们看关键的ImageServlet是怎么生成图片的:
1 public class ImageServlet extends HttpServlet { 2 public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException{ 3 BufferedImage bi = new BufferedImage(68,22,BufferedImage.TYPE_INT_RGB); 4 Graphics g = bi.getGraphics(); 5 Color c = new Color(200,150,255); 6 g.setColor(c); 7 g.fillRect(0, 0, 68, 22); 8 char[] ch = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".toCharArray(); 9 Random r = new Random(); 10 int len=ch.length,index; 11 StringBuffer sb = new StringBuffer(); 12 for(int i=0; i<4; i++){ 13 index = r.nextInt(len); 14 g.setColor(new Color(r.nextInt(88),r.nextInt(188),r.nextInt(255))); 15 g.drawString(ch[index]+"", (i*15)+3, 18); 16 sb.append(ch[index]); 17 } 18 request.getSession().setAttribute("piccode", sb.toString()); 19 ImageIO.write(bi, "JPG", response.getOutputStream()); 20 } 21 }
ImageServlet
如果要更生动的描述这种验证码是怎么样来实现的,那么就一个字“画”,听上去和第一种方法类似,还是比较low,但是用代码来自动“画”出验证码效率绝对翻了无数倍。我们来看上述代码,首先实例化了一个BufferedImage对象bi,bi是用来画出那张验证码图片的,然后用bi得到一支画笔g,用g画出了实体的矩形背景,接着用简单的逻辑通过画笔g调用Java中常用的drawString()方法在矩形上画出验证码字符,同时将字符串依次加入StringBuffer可变字符串对象中,最后存入jsp内置对象session中以便提交验证码后的比对,为了显示出验证码,我们还需将生成验证码图片以某种图片格式写入ImageIO流。
下面LoginServlet中可以看出,获取刚刚ImageServlet存入session的字符串就可以进行与验证码提交框中字符串的比对了,可以把字符串都变为小写或大写做一个忽略大小写的处理。
1 public class LoginServlet extends HttpServlet{ 2 public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException{ 3 String piccode = (String) request.getSession().getAttribute("piccode"); 4 String checkcode = request.getParameter("checkcode"); 5 checkcode = checkcode.toUpperCase(); 6 response.setContentType("text/html;charset=gbk"); 7 PrintWriter out = response.getWriter(); 8 if(checkcode.equals(piccode)){ 9 out.println("验证码输入正确!"); 10 }else{ 11 out.println("验证码输入错误!!!"); 12 } 13 out.flush(); 14 out.close(); 15 } 16 }
LoginServlet
下面是实现图例:
//未完,见(下)http://www.cnblogs.com/justcaxzm/p/5494959.html