驗證碼的生成和驗證

大多網站登陸時須要輸入一個驗證碼,這主要是基於安全性方面的考慮。在這裏將詳細的說明一下驗證碼的生成和驗證。javascript

首先是java文件(這段java主要寫了驗證碼圖片的生成及各類特效,好比旋轉、干擾線、噪點等,並將其用流的方式傳到前端頁面):html

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中的驗證碼做對比,再返回給前端):java

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;
    }
}
相關文章
相關標籤/搜索