基于spring,acegi,jcaptcha的验证码

首先,在你的web.xml里加入过滤器"Acegi Channel Processing Filter"如下:

<filter>
  <filter-name>Acegi Channel Processing Filter</filter-name>  
  <filter-class>org.acegisecurity.util.FilterToBeanProxy</filter-class>
  <init-param>
   <param-name>targetClass</param-name>
   <param-value>org.acegisecurity.securechannel.ChannelProcessingFilter</param-value>
  </init-param>
</filter>

<filter-mapping>
  <filter-name>Acegi Channel Processing Filter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

第二步,在你的bean的配置文件中加入如下bean:

<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
    /login.action=REQUIRES_CAPTCHA_BELOW_AVERAGE_TIME_IN_MILLIS_REQUESTS
   </value>
  </property>
</bean>


channelProcessingFilter的filterInvocationDefinitionSource属性中定义了哪些url将被拦截(需要验证码才能访问)

/login.action=REQUIRES_CAPTCHA_BELOW_AVERAGE_TIME_IN_MILLIS_REQUESTS

指定当用户登录提交login.action时,需要验证码,一共有四种验证支持,如下:

REQUIRES_CAPTCHA_BELOW_AVERAGE_TIME_IN_MILLIS_REQUESTS AlwaysTestBelowAverageTimeInMillisBetweenRequestsChannelProcessor (处理程序)

REQUIRES_CAPTCHA_AFTER_THRESOLD_IN_MILLIS AlwaysTestAfterTimeInMillisCaptchaChannelProcessor

REQUIRES_CAPTCHA_ABOVE_THRESOLD_REQUESTS AlwaysTestAfterMaxRequestsCaptchaChannelProcessor

REQUIRES_CAPTCHA_ONCE_ABOVE_THRESOLD_REQUESTS TestOnceAfterMaxRequestsCaptchaChannelProcessor

我选择了第一种.


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

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


<!-- captchaFormUrl属性指定了验证失败后页面的指向!!! -->
<bean id="captchaEntryPoint" class="org.acegisecurity.captcha.CaptchaEntryPoint">
  <property name="captchaFormUrl">
   <value>/index.action?login_error=2</value>
  </property>
</bean>

captchaValidationProcessingFilter拦截了所有的http请求,如果请求中有名字为"j_captcha_response"的参数,将调用CaptchaServiceProxy 接口的实现类来进行验证码图片的生成等操作.

<bean id="captchaValidationProcessingFilter" class="org.acegisecurity.captcha.CaptchaValidationProcessingFilter">
  <property name="captchaService">
   <ref bean="captchaService" />
  </property>
  <property name="captchaValidationParameter">
   <value>j_captcha_response</value>
  </property>
</bean>
   
<bean id="captchaService" class="com.demon.security.JCaptchaServiceProxyImpl" >
  <property name="jcaptchaService" ref="jcaptchaService" />
</bean>

<!-- jcaptchaService指定了用于生成验证码图片的类,不过这个生成的图片很难看,下面有一种生成自定义图片的方法-->

<bean id="jcaptchaService" class="com.octo.captcha.service.image.DefaultManageableImageCaptchaService" />

接着更改filterChainProxy的filterInvocationDefinitionSource属性,按顺序加入captchaValidationProcessingFilter,channelProcessingFilter两个过滤器,如下:

<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, logoutFilter,authenticationProcessingFilter,securityContextHolderAwareRequestFilter,anonymousProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor
   </value>
  </property>
</bean>

给httpSessionContextIntegrationFilter加入context属下如下:

<bean id="httpSessionContextIntegrationFilter" class="org.acegisecurity.context.HttpSessionContextIntegrationFilter">
<property name="context"><value>org.acegisecurity.captcha.CaptchaSecurityContextImpl</value></property>
</bean>

配置文件到此就结束了,然后是页面文件的登录表单

<s:form action="login.action" method="post">
<TABLE>
   <td>请输入右边的验证码</td>
   <td><input type="text" name="j_captcha_response"/>

       <img src="captcha-image.action"/></td>
  </tr>
</TABLE>
</s:form>

因为我是用的stucts2做为mvc框架,把作为验证码的img标签的src指定为"captcha-image.action",

然后在struct.xml配置相应的action如下:

<action name="captcha-image" class="com.demon.security.CaptchaImageCreateController"/>

即当页面加载时,会执行CaptchaImageCreateController类,代码如下:

package com.demon.security;

import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts2.ServletActionContext;
import org.springframework.beans.factory.InitializingBean;

import com.opensymphony.xwork2.ActionSupport;
import com.octo.captcha.service.image.ImageCaptchaService;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;

@SuppressWarnings("serial")
public class CaptchaImageCreateController extends ActionSupport implements InitializingBean {

private ImageCaptchaService jcaptchaService;

public String execute() throws Exception{
  HttpServletRequest request = ServletActionContext.getRequest();
  HttpServletResponse response = ServletActionContext.getResponse();
  byte[] captchaChallengeAsJpeg = null;
 
      ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();
             
        String captchaId = request.getSession().getId();


   //生成验证码图片,在这里我们只需要在spring的bean配置文件中更改jcaptchaService的实现,就可以生成不同的验证码图片

     BufferedImage challenge = jcaptchaService.getImageChallengeForID(captchaId,request.getLocale());
        JPEGImageEncoder jpegEncoder = JPEGCodec.createJPEGEncoder(jpegOutputStream);
        jpegEncoder.encode(challenge);

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

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

public void afterPropertiesSet() throws Exception {
  if(jcaptchaService == null){
   throw new RuntimeException("Image captcha service wasn`t set!");
  }
}

}

OK!!!!!!!!!!!!!!

##########################################################################

由于<bean id="jcaptchaService" class="com.octo.captcha.service.image.DefaultManageableImageCaptchaService" />

生成的图片确实比较丑,可以更改为以下实现:

<bean id="jcaptchaService" class="com.octo.captcha.service.multitype.GenericManageableCaptchaService">
  <constructor-arg index="0"><ref bean="imageEngine"/></constructor-arg>
  <constructor-arg index="1"><value>180</value></constructor-arg>
  <constructor-arg index="2"><value>180000</value></constructor-arg>
</bean>
<bean id="imageEngine" class="com.octo.captcha.engine.GenericCaptchaEngine">
  <constructor-arg index="0">
   <list>
    <ref bean="CaptchaFactory"/>
   </list>
  </constructor-arg>
</bean>

<bean id="CaptchaFactory" class="com.octo.captcha.image.gimpy.GimpyFactory" >
  <constructor-arg><ref bean="wordgen"/></constructor-arg>
  <constructor-arg><ref bean="wordtoimage"/></constructor-arg>
</bean>

<bean id="wordgen" class= "com.octo.captcha.component.word.wordgenerator.DictionaryWordGenerator" >
  <constructor-arg><ref bean="filedict"/></constructor-arg>
</bean>

<bean id="wordtoimage" class="com.octo.captcha.component.image.wordtoimage.ComposedWordToImage" >
  <constructor-arg index="0"><ref bean="fontGenRandom"/></constructor-arg>
  <constructor-arg index="1"><ref bean="backGenUni"/></constructor-arg>
  <constructor-arg index="2"><ref bean="simpleWhitePaster"/></constructor-arg>
</bean>

<bean id="filedict" class="com.octo.captcha.component.word.FileDictionary" >
  <constructor-arg index="0"><value>toddlist</value></constructor-arg>
</bean>

<bean id="fontGenRandom" class="com.octo.captcha.component.image.fontgenerator.RandomFontGenerator" >
  <!-- 验证码字体最小值 -->
  <constructor-arg index="0"><value>20</value></constructor-arg>
  <!-- 验证码字体最大值 -->
  <constructor-arg index="1"><value>20</value></constructor-arg>
  <constructor-arg index="2">
   <list>
    <ref bean="fontArial"/>
   </list>
  </constructor-arg>
</bean>

<bean id="fontArial" class="java.awt.Font" >
  <constructor-arg index="0"><value>Arial</value></constructor-arg>
  <constructor-arg index="1"><value>0</value></constructor-arg>
  <constructor-arg index="2"><value>10</value></constructor-arg>
</bean>

<bean id="backGenUni" class="com.octo.captcha.component.image.backgroundgenerator.UniColorBackgroundGenerator" >
  <!-- 验证码图片长度 -->
  <constructor-arg index="0"><value>80</value></constructor-arg>
  <!-- 验证码图片高度 -->
  <constructor-arg index="1"><value>25</value></constructor-arg>
</bean>

<bean id="simpleWhitePaster" class="com.octo.captcha.component.image.textpaster.SimpleTextPaster" >
  <!-- 验证码个数最小值 -->
  <constructor-arg type="java.lang.Integer" index="0">
   <value>4</value>
  </constructor-arg>
  <!-- 验证码个数最大值 -->
  <constructor-arg type="java.lang.Integer" index="1">
   <value>4</value>
  </constructor-arg>
  <!-- 验证码颜色 -->
  <constructor-arg type="java.awt.Color" index="2">
   <ref bean="colorGreen"/>
  </constructor-arg>
</bean>

<bean id="colorGreen" class="java.awt.Color" >
  <constructor-arg index="0"><value>0</value></constructor-arg>
  <constructor-arg index="1"><value>0</value></constructor-arg>
  <constructor-arg index="2"><value>255</value></constructor-arg>
</bean>

wish can help you best!!!

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