免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 32503 | 回复: 1
打印 上一主题 下一主题

验证码的生成和验证 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2015-06-01 09:29 |只看该作者 |倒序浏览
大多网站登录时需要输入一个验证码,这主要是基于安全性方面的考虑。在这里将详细的说明一下验证码的生成和验证。

首先是java文件(这段java主要写了验证码图片的生成及各种特效,比如旋转、干扰线、噪点等,并将其用流的方式传到前端页面):
  1. package com.servlet;
  2. import java.awt.BasicStroke;
  3. import java.awt.Color;
  4. import java.awt.Font;
  5. import java.awt.Graphics;
  6. import java.awt.Graphics2D;
  7. import java.awt.Stroke;
  8. import java.awt.image.BufferedImage;
  9. import java.io.IOException;
  10. import java.util.Random;
  11. import javax.imageio.ImageIO;
  12. import javax.servlet.ServletException;
  13. import javax.servlet.ServletOutputStream;
  14. import javax.servlet.http.HttpServlet;
  15. import javax.servlet.http.HttpServletRequest;
  16. import javax.servlet.http.HttpServletResponse;
  17. import javax.servlet.http.HttpSession;

  18. public class ImageServlet extends HttpServlet {
  19. public void doGet(HttpServletRequest request, HttpServletResponse response)
  20.    throws ServletException, IOException {
  21.             doPost(request, response);
  22. }
  23. public void doPost(HttpServletRequest request, HttpServletResponse response)
  24.   throws ServletException, IOException {
  25.   int width=100;//验证码图片宽度
  26.   int height=40;//验证码图片高度
  27.   BufferedImage image=new BufferedImage(width,height,BufferedImage.TYPE_3BYTE_BGR);
  28.   Graphics g=image.getGraphics();
  29.   Graphics2D g2d = (Graphics2D) g;
  30.   Random random=new Random();
  31.   g.setColor(Color.white);//背景颜色(或getRandColor(160,250))
  32.   g.fillRect(0, 0, width, height);//画背景
  33.   //g.setColor(getRandColor(0,255));//边框颜色
  34.   //      g.drawRect(0, 0, width-1, height-1);//画边框

  35. // 随机产生20条干扰线,使图象中的认证码不易被其它程序探测到
  36.   g.setColor(getRandColor(160,200));  
  37.   //Stroke stroke=new BasicStroke(3.0f);//设置线宽为3.0
  38.   for(int i=0;i<20;i++){
  39.    int x=random.nextInt(width);
  40.    int y=random.nextInt(height);
  41.    int x1=random.nextInt(20);
  42.    int y1=random.nextInt(20);
  43.    g.drawLine(x,y,x+x1,y+y1);
  44.    //g2d.setStroke(stroke);
  45.   }

  46. // 随机产生20点,使图象中的认证码不易被其它程序探测到  
  47.   g.setColor(getRandColor(160,200));
  48.   for(int i=0;i<20;i++){
  49.    int x=random.nextInt(width);
  50.    int y=random.nextInt(height);
  51.    g.drawLine(x, y, x, y);
  52.   }

  53. //随机生成不同的字体、字体样式和字体大小
  54.   String[] fontName = {"微软雅黑","黑体","Georgia","Verdana","Arial","Comic Sans MS","Lucida Console"};
  55.   int [] fontEffect = {Font.PLAIN, Font.ITALIC, Font.BOLD};
  56.   int [] fontSize = {28, 30, 32, 26};
  57.   Font[] fonts = new Font[fontName.length*fontEffect.length*fontSize.length];
  58.   int fontsIndex=0;
  59.   for(String str: fontName){
  60.       for(int effect: fontEffect){
  61.           for(int size : fontSize){
  62.               Font font = new Font(str, effect, size);
  63.               fonts[fontsIndex]=font;
  64.               fontsIndex = fontsIndex +1;
  65.           }
  66.       }
  67.   }
  68.   String s="abcdefghijknpqrstuvxyzABCDEFGHJKLNPQRSTUVXYZ23456789"; // 设置备选验证码
  69.   String sRand="";
  70.         // 用随机产生的颜色将验证码绘制到图像中。
  71.   int length = 4;  // 设置默认生成4个验证码
  72.   for(int i=0;i<length;i++){
  73.   g.setColor(new Color(20+random.nextInt(110), 20+random.nextInt(110), 20+random.nextInt(110))); // 生成随机颜色(因为是做前景,所以偏深)
  74.       g.setFont(fonts[random.nextInt(fonts.length)]);  //调用上方的随机字体
  75.    String ch=String.valueOf(s.charAt(random.nextInt(s.length())));

  76. //设置字体旋转
  77.    int zhuan = random.nextInt(20);
  78.    int fzhuan = -random.nextInt(20);
  79.       g2d.rotate(Math.toRadians(zhuan),25*(i-1),20);     /// 坐标系顺时针转
  80.       g2d.rotate(Math.toRadians(fzhuan),25*(i-1),20);    /// 坐标系逆时针转
  81.   
  82.       sRand+=ch;
  83.      g.drawString(ch, 18 * i + 15, 30); //将认证码用 drawString 函数显示到图象里

  84.    g2d.rotate(Math.toRadians(-1*zhuan),25*(i-1),20);
  85.    g2d.rotate(Math.toRadians(-1*fzhuan),25*(i-1),20);
  86.   }
  87.   //将生成的字符串存储在session中
  88.   HttpSession session=request.getSession();   
  89.   
  90. //在认证码的上端画一条不规则的线
  91.   int visit[] = new int[6];  
  92.   for (int i = 0; i < visit.length; i++) {  
  93.       visit[i] = 1 + (int) (Math.random() * 10);  
  94.   }
  95.   int visitValue = 0;  
  96. g.setColor(Color.BLACK);  
  97. int drawHigh[] = new int[6];  
  98. int drawwidth[] = new int[6];  
  99. //折点坐标  
  100. for (int i = 0; i < 6; i++) {  
  101.      drawHigh[i] = 40 - (int) (Math.ceil(visit[i] * 3.8));  
  102.      drawwidth[i] = 5 + i * 17;  
  103. }  
  104. //g2d.setXORMode(Color.WHITE);
  105.   g2d.setStroke(new BasicStroke(3.0f));  //折线粗细
  106.   g2d.setPaint(Color.gray);//折线的颜色
  107.   g2d.drawPolyline(drawwidth, drawHigh, 6);  //画折线  

  108.   session.setAttribute("checkCode", sRand);
  109.   g.dispose();//图像生效
  110.   //禁止图像缓存
  111.   response.setHeader("Pragma", "No-cache");
  112.   response.setHeader("Cache-Control", "no-cache");
  113.   response.setDateHeader("Expires", 0);   
  114.   response.setContentType("image/jpeg");
  115.   //创建二进制的输出流
  116.   ServletOutputStream sos=response.getOutputStream();
  117.         // 将图像输出到Servlet输出流中。
  118.         ImageIO.write(image, "jpeg", sos);
  119.         sos.flush();
  120.         sos.close();
  121. }
  122. public Color getRandColor(int lower,int upper){
  123.       Random random = new Random();
  124.       if(upper>255)
  125.        upper=255;
  126.       if(upper<1)
  127.        upper=1;
  128.       if(lower<1)
  129.        lower=1;
  130.       if(lower>255)
  131.        lower=255;
  132.       int r=lower+random.nextInt(upper-lower);
  133.       int g=lower+random.nextInt(upper-lower);
  134.       int b=lower+random.nextInt(upper-lower);
  135.       return new Color(r,g,b);
  136.     }
  137. }
复制代码
然后是前端的jsp展示页面(这里主要是写了一个方法来调用后端,将生成的验证码图片展示出来)
  1. <%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
  2. <%
  3. String path = request.getContextPath();
  4. String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
  5. %>
  6. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
  7. <html>
  8.   <head>
  9.     <base href="<%=basePath%>">
  10.     <title>验证码的生成和验证</title>  
  11.     <meta http-equiv="pragma" content="no-cache">
  12.     <meta http-equiv="cache-control" content="no-cache">
  13.     <meta http-equiv="expires" content="0">   

  14.     <script type="text/javascript"  src="http://code.jquery.com/jquery-1.9.1.js"></script>
  15.     <script type="text/javascript" language="javascript">
  16.           function changeImg(){
  17.               $("#img").attr("src", "ImageServlet?time="+new Date());
  18.         }
  19.           $(function(){
  20.                $("#button").click(function(){
  21.                   changeImg();
  22.                   var v_inputCode = document.getElementById("validate").value.toLowerCase();
  23.                   if(v_inputCode == ""){
  24.                       alert("请输入验证码");
  25.                   }else{
  26.                       $.post("<%=basePath%>test.htm",{inputCode:v_inputCode},
  27.                     function(data){
  28.                         data = $.parseJSON(data);
  29.                         if(data.test== 1){
  30.                             alert("请输入正确的验证码");
  31.                         }else{
  32.                             alert("验证码输入正确");
  33.                             location.href='../jsp/index.html';//跳转页面
  34.                         }
  35.                       });
  36.                   }
  37.             });
  38.           });
  39.     </script>
  40. </head>
  41.   
  42. <body>
  43.     <form  action="#">
  44.         <table>
  45.             <caption>验证码测试</caption>
  46.             <tr>
  47.                 <td>验证码</td>
  48.                 <td colspan="2">
  49.                     <input type="text" id="validate" />
  50.                     <a href='javascript:changeImg();' title="看不清请点我" >
  51.                         <img id="img" align="middle" src="ImageServlet" />
  52.                     </a>
  53.                 </td>
  54.             </tr>
  55.             <tr>
  56.                 <td colspan="2"><input id="button" type="button" value="查&nbsp;&nbsp;询" /></td>
  57.             </tr>
  58.          </table>
  59.     </form>
  60. </body>  
  61. </html>
复制代码
最后是验证(这里主要是将前端传入的用户输入的验证码与session中的验证码作对比,再返回给前端):
  1. import java.text.SimpleDateFormat;
  2. import java.util.ArrayList;
  3. import java.util.Date;
  4. import java.util.HashMap;
  5. import java.util.List;
  6. import java.util.Map;

  7. import javax.annotation.Resource;
  8. import javax.mail.Session;
  9. import javax.servlet.http.HttpServletRequest;
  10. import javax.servlet.http.HttpServletResponse;

  11. import net.sf.json.util.NewBeanInstanceStrategy;

  12. import org.omg.CORBA.PUBLIC_MEMBER;
  13. import org.springframework.stereotype.Controller;
  14. import org.springframework.web.bind.annotation.RequestMapping;
  15. import org.springframework.web.bind.annotation.RequestMethod;
  16. import org.springframework.web.bind.annotation.ResponseBody;

  17. import com.util.StringUtil;

  18. @Controller
  19. public class TestController {
  20.     @Resource(name = "stringutil")
  21.     private StringUtil stringUtil;
  22.    
  23.     @RequestMapping(value = "test.htm",method = RequestMethod.POST)
  24.     public @ResponseBody Map<String, Object> querycard(HttpServletRequest request,
  25.             HttpServletResponse response){
  26.         Map<String, Object> result = new HashMap<String, Object>();
  27.         String string = request.getSession().getAttribute("checkCode").toString();
  28.         Map<String, Object> requestMap = stringUtil.getParamsForJqgrid(request);
  29.         Map<String, Object> map = (Map<String, Object>) requestMap.get("paraMap");
  30.         if((string.toLowerCase()).equals(map.get("inputCode").toString().toLowerCase())){//不区分大小写(将两个值都转换成小写再进行比较)
  31.             result.put("test",0);//true
  32.         }else {
  33.             result.put("test",1);//false
  34.         }
  35.         return result;
  36.     }
  37. }
复制代码

论坛徽章:
0
2 [报告]
发表于 2019-05-13 15:45 |只看该作者
现在市场上出现很多提供验证码验证的第三方sdk,不需要自己写这么麻烦了,我本身之前有集成过一个SMSSDK这个,可以获取验证验证的,觉得还不错,有兴趣可以去了解下!
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP