spring+ jcaptcha(spring框架下的彩色验证码)

1、从jcaptcha官方网站下载jcaptcha的发行包,并将其发行包中的jar文件考贝到本地项目WEB-INF目录下的lib目录中。

官方网址 http://jcaptcha.sourceforge.net/

2、在web.xml文件中配置
 <servlet>
      <servlet-name>jcaptcha</servlet-name>
      <servlet-class>cn.hxex.order.core.jcaptcha.ImageCaptchaServlet</servlet-class>
      <load-on-startup>3</load-on-startup>
  </servlet>

  <servlet-mapping>
      <servlet-name>jcaptcha</servlet-name>
      <url-pattern>/captcha.jpg</url-pattern>
  </servlet-mapping>


3、jcaptcha在spring中的配置
    <bean id="channelProcessingFilter"
          class="org.acegisecurity.securechannel.ChannelProcessingFilter">
        <property name="channelDecisionManager">
            <ref local="channelDecisionManager"/> 
        </property>
        <property name="filterInvocationDefinitionSource">
            <value>
                CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
                PATTERN_TYPE_APACHE_ANT
                /j_security_check=REQUIRES_CAPTCHA_ONCE_ABOVE_THRESOLD_REQUESTS
            </value>
        </property>
    </bean>

    <bean id="channelDecisionManager"
          class="org.acegisecurity.securechannel.ChannelDecisionManagerImpl">
        <property name="channelProcessors"> 
            <list>
                <ref local="testOnceAfterMaxRequestsCaptchaChannelProcessor"/>
                <ref local="alwaysTestAfterTimeInMillisCaptchaChannelProcessor"/>
                <ref local="alwaysTestAfterMaxRequestsCaptchaChannelProcessor"/>
                <ref local="alwaysTestBelowAverageTimeInMillisBetweenRequestsChannelProcessor"/>
            </list>
        </property>
    </bean>

    <!-- REQUIRES_CAPTCHA_ONCE_ABOVE_THRESOLD_REQUESTS -->
    <bean id="testOnceAfterMaxRequestsCaptchaChannelProcessor"
          class="org.acegisecurity.captcha.TestOnceAfterMaxRequestsCaptchaChannelProcessor">
        <property name="thresold">
            <value>0</value>
        </property>
        <property name="entryPoint">
            <ref bean="captchaEntryPoint"/>
        </property>
    </bean>

    <!-- REQUIRES_CAPTCHA_ABOVE_THRESOLD_REQUESTS -->
    <bean id="alwaysTestAfterMaxRequestsCaptchaChannelProcessor"
          class="org.acegisecurity.captcha.AlwaysTestAfterMaxRequestsCaptchaChannelProcessor">
        <property name="thresold">
            <value>5</value>
        </property>
        <property name="entryPoint">
            <ref bean="captchaEntryPoint"/>
        </property>
    </bean>

    <!-- REQUIRES_CAPTCHA_AFTER_THRESOLD_IN_MILLIS -->
    <bean id="alwaysTestAfterTimeInMillisCaptchaChannelProcessor"
          class="org.acegisecurity.captcha.AlwaysTestAfterTimeInMillisCaptchaChannelProcessor">
        <property name="thresold">
            <value>5000</value>
        </property>
        <property name="entryPoint">
            <ref bean="captchaEntryPoint"/>
        </property>
    </bean>

    <!-- REQUIRES_CAPTCHA_BELOW_AVERAGE_TIME_IN_MILLIS_REQUESTS -->
     
    <bean
            id="alwaysTestBelowAverageTimeInMillisBetweenRequestsChannelProcessor"
            class="org.acegisecurity.captcha.AlwaysTestBelowAverageTimeInMillisBetweenRequestsChannelProcessor">
        <property name="thresold">
            <value>20000</value>
        </property>
        <property name="entryPoint">
            <ref bean="captchaEntryPoint"/>
        </property>
    </bean>

    <bean id="captchaEntryPoint"
          class="org.acegisecurity.captcha.CaptchaEntryPoint">
        <!--验证码验证失败后转向的页面!-->
        <property name="captchaFormUrl">
            <value>/admin/login.jsp?login_error=code_error</value>
        </property>
        <property name="includeOriginalRequest">
            <value>false</value>
        </property>
        <property name="includeOriginalParameters">
            <value>false</value>
        </property>
    </bean>

    <bean id="captchaValidationProcessingFilter"
          class="org.acegisecurity.captcha.CaptchaValidationProcessingFilter">
        <property name="captchaService">
            <ref bean="captchaService"/>
        </property>
        <property name="captchaValidationParameter" value="j_captcha_response"/>
    </bean>
    
    <!-- imageCaptchaService is injected into captchaImageCreateController as well as to captchaService beans -->
   <!--自己定义的实体类(注意路径!!)-->
    <bean id="captchaService" class="cn.hxex.order.core.jcaptcha.JCaptchaServiceProxyImpl">
        <property name="jcaptchaService" ref="imageCaptchaService"/>
    </bean>
    
    <bean id="imageCaptchaService" class="com.octo.captcha.service.image.DefaultManageableImageCaptchaService">
        <constructor-arg type="com.octo.captcha.service.captchastore.CaptchaStore" index="0">
            <ref bean="fastHashMapCaptchaStore"/>
        </constructor-arg>
        <!-- (1) which captcha Engine you use -->
        <constructor-arg type="com.octo.captcha.engine.CaptchaEngine" index="1">
            <ref bean="captchaEngineEx"/>
        </constructor-arg>
        <constructor-arg index="2">
            <value>180</value>
        </constructor-arg>
        <constructor-arg index="3">
            <value>100000</value>
        </constructor-arg>
        <constructor-arg index="4">
            <value>75000</value>
        </constructor-arg>
    </bean>

    <bean id="fastHashMapCaptchaStore" class="com.octo.captcha.service.captchastore.FastHashMapCaptchaStore"/>

    <!-- (2) you can define more than one captcha engine here -->
    <bean id="captchaEngineEx"
          class="cn.hxex.order.core.jcaptcha.engine.CaptchaEngineEx">      
    </bean>

         <bean id="filterChainProxy"
		class="org.acegisecurity.util.FilterChainProxy">
		<property name="filterInvocationDefinitionSource"> 
			<value>
				CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
				PATTERN_TYPE_APACHE_ANT
				/**=httpSessionContextIntegrationFilter,captchaValidationProcessingFilter,channelProcessingFilter,authenticationProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor
			</value>
		</property>
	</bean>

         <bean id="httpSessionContextIntegrationFilter"
		class="org.acegisecurity.context.HttpSessionContextIntegrationFilter">
		<!-- 将下面的property注释掉,验证码将无效!!! -->
		<property name="context">
			<value>
				org.acegisecurity.captcha.CaptchaSecurityContextImpl
			</value>
		</property>
	</bean>
·············省略了一些spring安全框架的bean,自己加去吧


4、编写jcaptcha的实体类

实体类包的路径一定要和spring配置文件里的路径一样

(1)CaptchaEngine 类
package cn.hxex.order.core.jcaptcha.engine;

import java.awt.Color;

import com.octo.captcha.component.image.backgroundgenerator.BackgroundGenerator;
import com.octo.captcha.component.image.backgroundgenerator
  .FunkyBackgroundGenerator;
import com.octo.captcha.component.image.fontgenerator.FontGenerator;
import com.octo.captcha.component.image.fontgenerator
  .TwistedAndShearedRandomFontGenerator;
import com.octo.captcha.component.image.textpaster.RandomTextPaster;
import com.octo.captcha.component.image.textpaster.TextPaster;
import com.octo.captcha.component.image.wordtoimage.ComposedWordToImage;
import com.octo.captcha.component.image.wordtoimage.WordToImage;
import com.octo.captcha.component.word.wordgenerator.RandomWordGenerator;
import com.octo.captcha.component.word.wordgenerator.WordGenerator;
import com.octo.captcha.engine.image.ListImageCaptchaEngine;
import com.octo.captcha.image.gimpy.GimpyFactory;

/**
 * SpringSide Custom的认证图片
 * 
 * @author cac
 */
public class CaptchaEngine extends ListImageCaptchaEngine {
  /**
   * @see ListImageCaptchaEngine
   */
  protected void buildInitialFactories() {
    WordGenerator wordGenerator 
      = new RandomWordGenerator("023456789");
    // nteger minAcceptedWordLength, Integer maxAcceptedWordLength,Color[]
    // textColors
    TextPaster textPaster = new RandomTextPaster(4,5, Color.WHITE);
    // Integer width, Integer height
    BackgroundGenerator backgroundGenerator 
      = new FunkyBackgroundGenerator(100,40);
    // Integer minFontSize, Integer maxFontSize
    FontGenerator fontGenerator = new TwistedAndShearedRandomFontGenerator(20, 22);
    WordToImage wordToImage = new ComposedWordToImage(fontGenerator,
        backgroundGenerator, textPaster);
    addFactory(new GimpyFactory(wordGenerator, wordToImage));
  }
}


(2)CaptchaEngineEx 类
package cn.hxex.order.core.jcaptcha.engine;

import java.awt.Color;

import com.octo.captcha.component.image.backgroundgenerator.BackgroundGenerator;
import com.octo.captcha.component.image.backgroundgenerator
  .GradientBackgroundGenerator;
import com.octo.captcha.component.image.color.SingleColorGenerator;
import com.octo.captcha.component.image.fontgenerator.FontGenerator;
import com.octo.captcha.component.image.fontgenerator.RandomFontGenerator;
import com.octo.captcha.component.image.textpaster.DecoratedRandomTextPaster;
import com.octo.captcha.component.image.textpaster.TextPaster;
import com.octo.captcha.component.image.textpaster.textdecorator
  .BaffleTextDecorator;
import com.octo.captcha.component.image.textpaster.textdecorator
  .LineTextDecorator;
import com.octo.captcha.component.image.textpaster.textdecorator.TextDecorator;
import com.octo.captcha.component.image.wordtoimage.ComposedWordToImage;
import com.octo.captcha.component.image.wordtoimage.WordToImage;
import com.octo.captcha.component.word.wordgenerator.RandomWordGenerator;
import com.octo.captcha.component.word.wordgenerator.WordGenerator;
import com.octo.captcha.engine.image.ListImageCaptchaEngine;
import com.octo.captcha.image.gimpy.GimpyFactory;


/**
 * Captcha增强版本
 * 
 * @author [email protected]
 * @modifyTime 21:01:52
 * @description 
 * <pre>
 *  安装 Captcha Instruction <br>
 *  1.add captchaValidationProcessingFilter 
 *    to applicationContext-acegi-security.xml<br>
 *  2.modify applicationContext-captcha-security.xml
 *    <ul>
 *    <li> make sure that captchaValidationProcessingFilter Call captchaService
      <li> config CaptchaEngine for captchaService (refer imageCaptchaService) 
      <li> write your own CaptchaEngine
      <li> config the following, so that We use CaptchaEngineEx to generate the 
          captcha image. 
      </ul>
          <constructor-arg
 *              type="com.octo.captcha.engine.CaptchaEngine" index="1"> 
 *              <ref bean="captchaEngineEx"/gt; </constructor-arg> 
 * </pre>
 */
public class CaptchaEngineEx extends ListImageCaptchaEngine {
  /**
   * ...
   */
  protected void buildInitialFactories() {
    
     //Set Captcha Word Length Limitation which should not over 6     
    Integer minAcceptedWordLength = new Integer(4);
    Integer maxAcceptedWordLength = new Integer(5);
    //Set up Captcha Image Size: Height and Width    
    Integer imageHeight = new Integer(40);
    Integer imageWidth = new Integer(100);
    
    //Set Captcha Font Size    
    Integer minFontSize = new Integer(20);
    Integer maxFontSize = new Integer(22);
    //We just generate digit for captcha source char Although you can use
    //abcdefg......xyz
    WordGenerator wordGenerator 
      = new RandomWordGenerator("023456789");
 
     //cyt and unruledboy proved that backgroup not a factor of Security. A
     //captcha attacker won't affaid colorful backgroud, so we just use white
     //color, like google and hotmail.  
    BackgroundGenerator backgroundGenerator = new GradientBackgroundGenerator(
        imageWidth, imageHeight, Color.white, Color.white);
  
     //font is not helpful for security but it really increase difficultness for
     //attacker     
    FontGenerator fontGenerator = new RandomFontGenerator(minFontSize,
        maxFontSize);    
     // Note that our captcha color is Blue     
    SingleColorGenerator scg = new SingleColorGenerator(Color.blue);
  
     //decorator is very useful pretend captcha attack. we use two line text
     //decorators.
     
    LineTextDecorator lineDecorator = new LineTextDecorator(1, Color.blue);
    // LineTextDecorator line_decorator2 = new LineTextDecorator(1, Color.blue);
    TextDecorator[] textdecorators = new TextDecorator[1];

    textdecorators[0] = lineDecorator;
    // textdecorators[1] = line_decorator2;

    TextPaster textPaster = new DecoratedRandomTextPaster(
        minAcceptedWordLength, maxAcceptedWordLength, scg,
        new TextDecorator[] { new BaffleTextDecorator(new Integer(1),
            Color.white) });

    //ok, generate the WordToImage Object for logon service to use.
    WordToImage wordToImage = new ComposedWordToImage(
        fontGenerator, backgroundGenerator, textPaster);
    addFactory(new GimpyFactory(wordGenerator, wordToImage));
  }

}


(3)ImageCaptchaServlet 类

package cn.hxex.order.core.jcaptcha;

import com.octo.captcha.service.CaptchaServiceException;
import com.octo.captcha.service.image.ImageCaptchaService;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
import org.apache.commons.lang.StringUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

/**
 * Servlet generates CAPTCHA jpeg images based on the JCAPTCHA package. It's
 * configured via spring, and requires a ImageCaptchaService bean with the
 * id=imageCaptchaService
 * 基于JCAPTCHA生成CAPTCHA jpeg图片的Servlet。它通过Spring进行配置,并且set一个
 * 类型为ImageCaptchaService,id为imageCaptchaService的bean
 * @author Jason Thrasher
 */
@SuppressWarnings("serial")
public class ImageCaptchaServlet extends HttpServlet {
  /**
   * Captcha Service Name
   */
  private String captchaServiceName = "imageCaptchaService";
  /**
   * @see HttpServlet#init(ServletConfig)
   */
  public void init(ServletConfig servletConfig) throws ServletException {
    if (StringUtils.isNotBlank(servletConfig
        .getInitParameter("captchaServiceName"))) {
      captchaServiceName = servletConfig.getInitParameter("captchaServiceName");
    }

    super.init(servletConfig);
  }
  /**
   * @see HttpServlet#doGet()
   */
  protected void doGet(HttpServletRequest httpServletRequest,
      HttpServletResponse httpServletResponse) throws ServletException,
      IOException {

    byte[] captchaChallengeAsJpeg = null;
    // the output stream to render the captcha image as jpeg into
    ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();
    try {
      // get the image captcha service defined via the SpringFramework
      ApplicationContext ctx = WebApplicationContextUtils
          .getRequiredWebApplicationContext(getServletContext());
      Object bean = ctx.getBean(captchaServiceName);
      ImageCaptchaService imageCaptchaService = (ImageCaptchaService) bean;

      // get the session id that will identify the generated captcha.
      // the same id must be used to validate the response, the session id
      // is a good candidate!
      String captchaId = httpServletRequest.getSession().getId();
      // call the ImageCaptchaService getChallenge method
      BufferedImage challenge = imageCaptchaService.getImageChallengeForID(
          captchaId, httpServletRequest.getLocale());

      // a jpeg encoder
      JPEGImageEncoder jpegEncoder = JPEGCodec
          .createJPEGEncoder(jpegOutputStream);
      jpegEncoder.encode(challenge);
    } catch (IllegalArgumentException e) {
      httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND);
      return;
    } catch (CaptchaServiceException e) {
      httpServletResponse
          .sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
      return;
    }

    captchaChallengeAsJpeg = jpegOutputStream.toByteArray();
    // flush it in the response
    httpServletResponse.setHeader("Cache-Control", "no-store");
    httpServletResponse.setHeader("Pragma", "no-cache");
    httpServletResponse.setDateHeader("Expires", 0);
    httpServletResponse.setContentType("image/jpeg");
    ServletOutputStream responseOutputStream = httpServletResponse
        .getOutputStream();
    responseOutputStream.write(captchaChallengeAsJpeg);
    responseOutputStream.flush();
    responseOutputStream.close();
  }
}


(4)JCaptchaServiceProxyImpl 类
package cn.hxex.order.core.jcaptcha;

import com.octo.captcha.service.CaptchaService;
import com.octo.captcha.service.CaptchaServiceException;
import org.acegisecurity.captcha.CaptchaServiceProxy;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * 实现 CaptchaServiceProxy 用于acegi来校验,由spring注入jcaptchaService
 * 
 * @author [email protected]
 */
public class JCaptchaServiceProxyImpl implements CaptchaServiceProxy {
  /**
   * Log for the class
   */
  protected static Log log = LogFactory.getLog(JCaptchaServiceProxyImpl.class);
  /**
   * instance of CaptchaService.
   */
  private CaptchaService jcaptchaService;
  
  /**
   * @see {@link CaptchaServiceProxy#validateReponseForId(String, Object)}
   */
  public boolean validateReponseForId(String id, Object response) {
    log.debug("validating captcha response");

    try {
      boolean isHuman = jcaptchaService.validateResponseForID(id, response)
          .booleanValue();
      if (isHuman) {
        log.debug("captcha passed");
      } else {
        log.warn("captcha failed");
      }
      return isHuman;

    } catch (CaptchaServiceException cse) {
      // fixes known bug in JCaptcha
      log.warn("captcha validation failed due to exception", cse);
      return false;
    }
  }

  public void setJcaptchaService(CaptchaService jcaptchaService) {
    this.jcaptchaService = jcaptchaService;
  }
}

你可能感兴趣的:(spring,框架,bean,servlet,Acegi)