開源驗證碼captcha引入方案

通常來說一個B/S項目基本都會用到驗證碼,用於用戶登錄或註冊,以此提高項目的安全性,而目前仍存在一些網站的應用環境比較特殊,使用人羣分部較廣,所以需要考慮ie瀏瀏覽器的兼容性,衆所周知,ie一代比一代坑,9以下和9以上差異非常大,第三方驗證碼都很少有兼容ie9以下的。然而由於國情的特殊,仍然有一大部分人在使用ie8甚至更低版本的瀏覽器。所以我用了patcha,這是一款兼容ie7以上所有版本 (7以下沒做測試)的驗證碼jar包,接入非常方便,效果也不錯。
首先,servlet中的代碼

package org.captcha.servlet;

import java.awt.Color;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Properties;
import java.util.Random;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.patchca.color.ColorFactory;
import org.patchca.color.SingleColorFactory;
import org.patchca.filter.predefined.CurvesRippleFilterFactory;
import org.patchca.filter.predefined.DiffuseRippleFilterFactory;
import org.patchca.filter.predefined.DoubleRippleFilterFactory;
import org.patchca.filter.predefined.MarbleRippleFilterFactory;
import org.patchca.filter.predefined.WobbleRippleFilterFactory;
import org.patchca.service.ConfigurableCaptchaService;
import org.patchca.utils.encoder.EncoderHelper;
import org.patchca.word.RandomWordFactory;
public class CaptchaServlet extends HttpServlet {
private static final long serialVersionUID = 4968328161261528097L;
private static ConfigurableCaptchaService cs = null;
private static ColorFactory cf = null;
private static RandomWordFactory wf = null;
private static Random r = new Random();
private static CurvesRippleFilterFactory crff = null;
private static MarbleRippleFilterFactory mrff = null;
private static DoubleRippleFilterFactory drff = null;
private static WobbleRippleFilterFactory wrff = null;
private static DiffuseRippleFilterFactory dirff = null;
/**驗證碼字符串長度,默認4*/
private static Integer randomCodeLength=4;
/**驗證碼圖片寬度,默認120*/
private static  Integer randomCodeWidth=120;
/**驗證碼圖片高度,默認50*/
private static Integer randomCodeHight=50;
/**驗證碼樣式
 * 1 彎曲狀
 * 2 搖擺裝
 * 3 搖晃
 * 4 散開
 * 5 大理石
 * 6 隨機(默認)
 * */
private static Integer randomCodeType=6;

/**驗證碼session中Attribute的Name*/
private static String randomCodeSessionAttributeName="PATCHCA";

@Override
public void init() throws ServletException {
    super.init();
    cs = new ConfigurableCaptchaService();
    cf = new SingleColorFactory(new Color(25, 60, 170));
    wf = new RandomWordFactory();
    crff = new CurvesRippleFilterFactory(cs.getColorFactory());
    drff = new DoubleRippleFilterFactory();
    wrff = new WobbleRippleFilterFactory();
    dirff = new DiffuseRippleFilterFactory();
    mrff = new MarbleRippleFilterFactory();
    cs.setWordFactory(wf);
    cs.setColorFactory(cf);
    cs.setWidth(randomCodeWidth);
    cs.setHeight(randomCodeHight);

    randomCodeLength=Integer.valueOf(null==this.getInitParameter("randomCodeLength")?"4":this.getInitParameter("randomCodeLength"));
    randomCodeWidth=Integer.valueOf(null==this.getInitParameter("randomCodeWidth")?"120":this.getInitParameter("randomCodeWidth"));
    randomCodeHight=Integer.valueOf(null==this.getInitParameter("randomCodeHight")?"50":this.getInitParameter("randomCodeHight"));
    randomCodeType=Integer.valueOf(null==this.getInitParameter("randomCodeType")?"6":this.getInitParameter("randomCodeType"));
    randomCodeSessionAttributeName=null==this.getInitParameter("randomCodeSessionAttributeName")?"PATCHCA":this.getInitParameter("randomCodeSessionAttributeName");

}
@Override
public void destroy() {
    wf = null;
    cf = null;
    cs = null;
    super.destroy();
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
    response.setContentType("image/png");
    response.setHeader("cache", "no-cache");
    wf.setMaxLength(randomCodeLength);
    wf.setMinLength(randomCodeLength);
    HttpSession session = request.getSession(true);
    OutputStream os = response.getOutputStream();
    int typeCode=randomCodeType;
    if(typeCode==6)
    {
        typeCode=r.nextInt(5);
    }

    //隨機產生5種效果(filter)
    switch (typeCode) {
    case 1:
        cs.setFilterFactory(crff);
        break;
    case 2:
        cs.setFilterFactory(mrff);
        break;
    case 3:
        cs.setFilterFactory(drff);
        break;
    case 4:
        cs.setFilterFactory(wrff);
        break;
    case 5:
        cs.setFilterFactory(dirff);
        break;
    default:
        cs.setFilterFactory(crff);
        break;

    }
    //這裏可以生成彩色驗證碼
/*  final Random random = new Random();
     cs.setColorFactory(new SingleColorFactory(new Color(25, 60, 170)));
     cs.setColorFactory(new ColorFactory() {
         @Override
         public Color getColor(int x) {
             int[] c = new int[3];
             int i = random.nextInt(c.length);
             for (int fi = 0; fi < c.length; fi++) {
                 if (fi == i) {
                     c[fi] = random.nextInt(71);
                 } else {
                     c[fi] = random.nextInt(256);
                 }
             }
             return new Color(c[0], c[1], c[2]);
         }
     });*/
    String patchca= EncoderHelper.getChallangeAndWriteImage(cs, "png", os);
    session.setAttribute(randomCodeSessionAttributeName, patchca);
    os.flush();
    os.close();
    }
}

web.xml中的配置

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <display-name>patchattest</display-name>
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
  <servlet>
        <servlet-name>patchca</servlet-name>
        <servlet-class>org.captcha.servlet.CaptchaServlet</servlet-class>
         <init-param><param-name>randomCodeType</param-name><param-value>3</param-value></init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>patchca</servlet-name>
        <url-pattern>/patchca.png</url-pattern>
</servlet-mapping>
</web-app>

jsp中的代碼,注意點擊事件後面跟的隨機數,用於改變圖片url防止瀏覽器緩存不清,點擊時重點內容圖片不變動。

<%@ 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>My JSP 'index.jsp' starting page</title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="This is my page">
    <!--
    <link rel="stylesheet" type="text/css" href="styles.css">
    -->
  </head>

  <body>
    This is my JSP page. <br>
    <table><tr>
<!-- patchca.png和servlet中的<url-pattern>對應 -->
        <td><img src="patchca.png" alt="驗證碼" 
style="cursor:pointer;vertical-align:text-bottom;"
                onclick="this.src=this.src+'?'+Math.random();"></td>
        <td valign="top">
            <form method="POST">
                <br>
                驗證碼:<input type="text" name="patchcafield">
                <br />
                <input type="submit" name="submit">
            </form></td></tr></table>
    <br /><br /><br /><br />

  </body>
</html>

效果
普通效果

彩色效果

上面這種方式原生serlvlet的寫法應該沒人用了,現在都是用框架,這更加簡單,不需要任何配置,這邊用struts
action中的代碼,action返回的結果是一個圖片流,頁面上直接用img標籤可以接收到。

import java.awt.Color;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Random;

import javax.servlet.http.HttpServletResponse;

import org.apache.struts2.ServletActionContext;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.ParentPackage;
import org.patchca.color.ColorFactory;
import org.patchca.color.SingleColorFactory;
import org.patchca.filter.predefined.CurvesRippleFilterFactory;
import org.patchca.filter.predefined.DiffuseRippleFilterFactory;
import org.patchca.filter.predefined.DoubleRippleFilterFactory;
import org.patchca.filter.predefined.MarbleRippleFilterFactory;
import org.patchca.filter.predefined.WobbleRippleFilterFactory;
import org.patchca.service.ConfigurableCaptchaService;
import org.patchca.utils.encoder.EncoderHelper;
import org.patchca.word.RandomWordFactory;

import com.jshop.action.backstage.base.BaseTAction;
import com.opensymphony.xwork2.ActionContext;

@Namespace("/frontstage/buyers")
@ParentPackage("jshop")
public class CaptchaAction extends BaseTAction{

    /**
     *patchca驗證碼
     *@author tang
     */
    private static final long serialVersionUID = 1L;
    private static ConfigurableCaptchaService cs = null;
    private static ColorFactory cf = null;
    private static RandomWordFactory wf = null;
    private static Random r = new Random();
    private static CurvesRippleFilterFactory crff = null;
    private static MarbleRippleFilterFactory mrff = null;
    private static DoubleRippleFilterFactory drff = null;
    private static WobbleRippleFilterFactory wrff = null;
    private static DiffuseRippleFilterFactory dirff = null;
    /**驗證碼字符串長度,默認4*/
    private static Integer randomCodeLength=4;
    /**驗證碼圖片寬度,默認120*/
    private static  Integer randomCodeWidth=120;
    /**驗證碼圖片高度,默認50*/
    private static Integer randomCodeHight=50;
    /**驗證碼樣式
     * 1 彎曲狀
     * 2 搖擺裝
     * 3 搖晃
     * 4 散開
     * 5 大理石
     * 6 隨機(默認)
     * */
    private static Integer randomCodeType=6;
    /**驗證碼session中Attribute的Name*/
    private static String randomCodeSessionAttributeName="PATCHCA";



    /**
     * 生成驗證碼
     * @author tang
     * @throws IOException 
     */
    @Action("/getCaptcha")
    public void getCaptcha(){
        cs = new ConfigurableCaptchaService();
        cf = new SingleColorFactory(new Color(25, 60, 170));
        wf = new RandomWordFactory();
        crff = new CurvesRippleFilterFactory(cs.getColorFactory());
        drff = new DoubleRippleFilterFactory();
        wrff = new WobbleRippleFilterFactory();
        dirff = new DiffuseRippleFilterFactory();
        mrff = new MarbleRippleFilterFactory();
        cs.setWordFactory(wf);
        cs.setColorFactory(cf);
        cs.setWidth(randomCodeWidth);
        cs.setHeight(randomCodeHight);

        randomCodeLength=Integer.valueOf(randomCodeLength);
        randomCodeWidth=Integer.valueOf(randomCodeWidth);
        randomCodeHight=Integer.valueOf(randomCodeHight);
        randomCodeType=Integer.valueOf(randomCodeType);
        randomCodeSessionAttributeName=null==randomCodeSessionAttributeName?"PATCHCA":randomCodeSessionAttributeName;
        HttpServletResponse response = ServletActionContext.getResponse();
        response.setContentType("image/png");
        response.setHeader("cache", "no-cache");
        wf.setMaxLength(randomCodeLength);
        wf.setMinLength(randomCodeLength);
        OutputStream os;
        try {
            os = response.getOutputStream();
            int typeCode=randomCodeType;
            if(typeCode==6)
            {
                typeCode=r.nextInt(5);
            }

            //隨機產生5種效果(filter)
            switch (typeCode) {
            case 1:
                cs.setFilterFactory(crff);
                break;
            case 2:
                cs.setFilterFactory(mrff);
                break;
            case 3:
                cs.setFilterFactory(drff);
                break;
            case 4:
                cs.setFilterFactory(wrff);
                break;
            case 5:
                cs.setFilterFactory(dirff);
                break;
            default:
                cs.setFilterFactory(crff);
                break;

            }
            final Random random = new Random();
             cs.setColorFactory(new SingleColorFactory(new Color(25, 60, 170)));
             cs.setColorFactory(new ColorFactory() {
                 @Override
                 public Color getColor(int x) {
                     int[] c = new int[3];
                     int i = random.nextInt(c.length);
                     for (int fi = 0; fi < c.length; fi++) {
                         if (fi == i) {
                             c[fi] = random.nextInt(71);
                         } else {
                             c[fi] = random.nextInt(256);
                         }
                     }
                     return new Color(c[0], c[1], c[2]);
                 }
             });
            String patchca= EncoderHelper.getChallangeAndWriteImage(cs, "png", os);
            System.out.println(patchca);
            if(os!=null){
                os.close();
            }
                 ActionContext.getContext().getSession().put(randomCodeSessionAttributeName, patchca);
            }catch(Exception e){
            System.err.println("遠程主機關閉了一個現有的鏈接");
            }
    }
}

html代碼

<img  id="patchca" src="getCaptcha.action" alt="驗證碼" style="cursor:pointer;vertical-align:text-bottom;"onclick="this.src=this.src+'?random='+Math.random();"/>

大小,顏色,樣式都可以根據自己需要調整,用的都是awt下的Color類(好冷門的GUI的東西)
總結一下patcha的優點:全瀏覽器兼容、低依賴整合方便、安全性足夠,響應速度很快。
用到的jar包,也是唯一的一個jar包
http://download.csdn.net/detail/qq_36289377/9887404

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章