验证码的生成和验证

大多网站登录时需要输入一个验证码,这主要是基于安全性方面的考虑。在这里将详细的说明一下验证码的生成和验证。

首先是java文件(这段java主要写了验证码图片的生成及各种特效,比如旋转、干扰线、噪点等,并将其用流的方式传到前端页面):

package com.servlet;
import java.awt.BasicStroke;
import java.awt.Color; 
import java.awt.Font; 
import java.awt.Graphics; 
import java.awt.Graphics2D;
import java.awt.Stroke;
import java.awt.image.BufferedImage; 
import java.io.IOException; 
import java.util.Random; 
import javax.imageio.ImageIO; 
import javax.servlet.ServletException; 
import javax.servlet.ServletOutputStream; 
import javax.servlet.http.HttpServlet; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 
import javax.servlet.http.HttpSession; 

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

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

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

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

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

   g2d.rotate(Math.toRadians(-1*zhuan),25*(i-1),20);
   g2d.rotate(Math.toRadians(-1*fzhuan),25*(i-1),20);
  } 
  //将生成的字符串存储在session中 
  HttpSession session=request.getSession();   
  
//在认证码的上端画一条不规则的线
  int visit[] = new int[6];  
  for (int i = 0; i < visit.length; i++) {  
      visit[i] = 1 + (int) (Math.random() * 10);  
  }
  int visitValue = 0;  
 g.setColor(Color.BLACK);  
 int drawHigh[] = new int[6];  
 int drawwidth[] = new int[6];  
 //折点坐标  
 for (int i = 0; i < 6; i++) {  
     drawHigh[i] = 40 - (int) (Math.ceil(visit[i] * 3.8));  
     drawwidth[i] = 5 + i * 17;  
 }  
 //g2d.setXORMode(Color.WHITE); 
  g2d.setStroke(new BasicStroke(3.0f));  //折线粗细
  g2d.setPaint(Color.gray);//折线的颜色 
  g2d.drawPolyline(drawwidth, drawHigh, 6);  //画折线  
 
  session.setAttribute("checkCode", sRand); 
  g.dispose();//图像生效 
  //禁止图像缓存 
  response.setHeader("Pragma", "No-cache"); 
  response.setHeader("Cache-Control", "no-cache"); 
  response.setDateHeader("Expires", 0);   
  response.setContentType("image/jpeg"); 
  //创建二进制的输出流 
  ServletOutputStream sos=response.getOutputStream(); 
        // 将图像输出到Servlet输出流中。 
        ImageIO.write(image, "jpeg", sos); 
        sos.flush(); 
        sos.close(); 
} 
public Color getRandColor(int lower,int upper){ 
      Random random = new Random(); 
      if(upper>255) 
       upper=255; 
      if(upper<1) 
       upper=1; 
      if(lower<1) 
       lower=1; 
      if(lower>255) 
       lower=255; 
      int r=lower+random.nextInt(upper-lower); 
      int g=lower+random.nextInt(upper-lower); 
      int b=lower+random.nextInt(upper-lower); 
      return new Color(r,g,b); 
    } 
} 

 

然后是前端的jsp展示页面(这里主要是写了一个方法来调用后端,将生成的验证码图片展示出来)

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">
    <title>验证码的生成和验证</title>  
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    

    <script type="text/javascript"  src="http://code.jquery.com/jquery-1.9.1.js"></script>
    <script type="text/javascript" language="javascript"> 
          function changeImg(){
              $("#img").attr("src", "ImageServlet?time="+new Date());
        } 
          $(function(){
               $("#button").click(function(){
                  changeImg();
                  var v_inputCode = document.getElementById("validate").value.toLowerCase();
                  if(v_inputCode == ""){
                      alert("请输入验证码");
                  }else{
                      $.post("<%=basePath%>test.htm",{inputCode:v_inputCode},
                    function(data){
                        data = $.parseJSON(data);
                        if(data.test== 1){
                            alert("请输入正确的验证码");
                        }else{
                            alert("验证码输入正确");
                            location.href='../jsp/index.html';//跳转页面
                        }
                      });
                  }
            });
          });
    </script> 
 </head>
  
 <body>
    <form  action="#"> 
        <table>
            <caption>验证码测试</caption>
            <tr>
                <td>验证码</td>
                <td colspan="2">
                    <input type="text" id="validate" />
                    <a href='javascript:changeImg();' title="看不清请点我" >
                        <img id="img" align="middle" src="ImageServlet" />
                    </a>
                </td>
            </tr>
            <tr>
                <td colspan="2"><input id="button" type="button" value="查&nbsp;&nbsp;询" /></td>
            </tr>
         </table>
    </form>
</body>  
</html>

 

最后是验证(这里主要是将前端传入的用户输入的验证码与session中的验证码作对比,再返回给前端):

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.mail.Session;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sf.json.util.NewBeanInstanceStrategy;

import org.omg.CORBA.PUBLIC_MEMBER;
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.ResponseBody;

import com.util.StringUtil;

@Controller
public class TestController {
    @Resource(name = "stringutil")
    private StringUtil stringUtil;
    
    @RequestMapping(value = "test.htm",method = RequestMethod.POST)
    public @ResponseBody Map<String, Object> querycard(HttpServletRequest request,
            HttpServletResponse response){
        Map<String, Object> result = new HashMap<String, Object>();
        String string = request.getSession().getAttribute("checkCode").toString();
        Map<String, Object> requestMap = stringUtil.getParamsForJqgrid(request);
        Map<String, Object> map = (Map<String, Object>) requestMap.get("paraMap");
        if((string.toLowerCase()).equals(map.get("inputCode").toString().toLowerCase())){//不区分大小写(将两个值都转换成小写再进行比较)
            result.put("test",0);//true
        }else {
            result.put("test",1);//false
        }
        return result;
    }
}
posted @ 2014-03-11 14:41  INTIME-DEV  阅读(2203)  评论(0编辑  收藏  举报