欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring+Hibernate+JSF+Ajax4jsf+Acegi+jCaptcha 做登录模块 博客分类: spring AcegiJSFSpringHibernateBean 

程序员文章站 2024-02-03 14:08:16
...

带 图片验证码的用户登录是一个系统中很常见的模块,在Java EE中有很多不同的实现,而开源世界中又给我们提供了很多优秀的框架,从而减少了我们的编码量,下面给大家简单介绍一下用Spring+ Hibernate+JSF+Ajax4jsf+Acegi+jCaptcha 如何构建一个登录模块:    我使用这些框架的版本如下:
    Spring 2.0.1
    Hibernate 3.2
    JSF 1.2
    Acegi 1.0.5
    jCaptcha 1.0-RC6
    首先建表USERTEST,和ROLETEST,作为用户表和角色表
CREATE TABLE USERTEST
(
  USERID    NUMBER                              NOT NULL,
  USERNAME  VARCHAR2(20 CHAR)                   NOT NULL,
  PASSWORD  VARCHAR2(100 CHAR)                  NOT NULL,
  STATUS    NUMBER                              DEFAULT 1                     NOT NULL,
  ROLEID    NUMBER                              NOT NULL
)

CREATE TABLE ROLETEST
(
  ROLEID    NUMBER                              NOT NULL,
  ROLENAME  VARCHAR2(50 CHAR)                   NOT NULL,
  ROLEDESC  VARCHAR2(50 CHAR)
)

    同时给ROLETEST表添加一条记录:1    ROLE_USER    普通用户
    再给USERTEST表添加一条记录:1    admin    123    1    1
    对应的hbm.xml文件就相信大家都会写,如果用eclipse开发的话,可以使用HibernateSynchronizer插件,我使用的版本是 3.1.9
    接下来就要给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"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd "
id="WebApp_ID" version="2.5">
<display-name>Demo</display-name>
<welcome-file-list>
  <welcome-file>index.html</welcome-file>
  <welcome-file>index.htm</welcome-file>
  <welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>
   /WEB-INF/classes/applicationContext.xml
  </param-value>
</context-param>
<context-param>
  <param-name>javax.faces.CONFIG_FILES</param-name>
  <param-value>/WEB-INF/faces-config.xml</param-value>
</context-param>
<listener>
  <listener-class>
   org.springframework.web.context.ContextLoaderListener
  </listener-class>
</listener>
<listener>
  <listener-class>
   org.acegisecurity.ui.session.HttpSessionEventPublisher
  </listener-class>
</listener>
<listener>
  <listener-class>
   com.sun.faces.config.ConfigureListener
  </listener-class>
</listener>
<filter>
  <filter-name>OpenSessionInView</filter-name>
  <filter-class>
   org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
  </filter-class>
  <init-param>
   <param-name>singleSession</param-name>
   <param-value>true</param-value>
  </init-param>
</filter>
<filter-mapping>
  <filter-name>OpenSessionInView</filter-name>
  <url-pattern>*.jsf</url-pattern>
</filter-mapping>
<filter>
  <filter-name>Acegi Filter Chain Proxy</filter-name>
  <filter-class>
   org.acegisecurity.util.FilterToBeanProxy
  </filter-class>
  <init-param>
   <param-name>targetClass</param-name>
   <param-value>
    org.acegisecurity.util.FilterChainProxy
   </param-value>
  </init-param>
</filter>
<filter-mapping>
  <filter-name>Acegi Filter Chain Proxy</filter-name>
  <url-pattern>/*</url-pattern>
  <dispatcher>FORWARD</dispatcher>
  <dispatcher>REQUEST</dispatcher>
</filter-mapping>
<filter>
  <display-name>Ajax4jsf Filter</display-name>
  <filter-name>ajax4jsf</filter-name>
  <filter-class>org.ajax4jsf.Filter</filter-class>
  </filter>
  
  <filter-mapping>
  <filter-name>ajax4jsf</filter-name>
  <servlet-name>Faces Servlet</servlet-name>
  <dispatcher>REQUEST</dispatcher>
  <dispatcher>FORWARD</dispatcher>
  <dispatcher>INCLUDE</dispatcher>
  </filter-mapping>


<servlet>
  <servlet-name>Faces Servlet</servlet-name>
  <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
  <servlet-name>Faces Servlet</servlet-name>
  <url-pattern>*.jsf</url-pattern>
</servlet-mapping>
</web-app>

    然后Spring的applicationContext.xml,在这里面你需要配置数据库连接、hibernate的各种策略、Acegi安全设置、 jCaptcha设置等等:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/

Spring+Hibernate+JSF+Ajax4jsf+Acegi+jCaptcha 做登录模块

www.firnow.com    时间 : 2008-02-03  作者:佚名   编辑:本站 点击:  2469 [ 评论 ]

<script src="http://dev.firnow.com/ad/2010/article/ad4.js"></script><script type="text/javascript">&lt;!-- google_ad_client = &quot;pub-2974889429954990&quot;; /* 468x15, 创建于 10-4-24 */ google_ad_slot = &quot;8838741374&quot;; google_ad_width = 468; google_ad_height = 15; //--&gt; </script><script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"> </script><script src="http://pagead2.googlesyndication.com/pagead/expansion_embed.js"></script><script src="http://googleads.g.doubleclick.net/pagead/test_domain.js"></script><script>google_protectAndRun(&quot;ads_core.google_render_ad&quot;, google_handleError, google_render_ad);</script>
<script src="http://dev.firnow.com/ad/2010/article/ad5.js"></script><script type="text/javascript"> cpro_client='diybl_cpr'; cpro_at='text_image'; cpro_161=3; cpro_flush=2; cpro_w=300; cpro_h=250; cpro_template='text_default_300_250'; cpro_cbd='#FFFFFF'; cpro_cbg='#FFFFFF'; cpro_ctitle='#215670'; cpro_cdesc='#444444'; cpro_curl='#808080'; cpro_cflush='#e10900'; cpro_uap=1; cpro_cad=1; cpro_channel=4; </script><script src="http://cpro.baidu.com/cpro/ui/cp.js" type="text/javascript"></script>
-
<script src="http://dev.firnow.com/ad/2010/article/ad6.js"></script><script type="text/javascript"> cpro_client='diybl_cpr'; cpro_at='text_image'; cpro_161=3; cpro_flush=2; cpro_w=300; cpro_h=250; cpro_template='text_default_300_250'; cpro_cbd='#FFFFFF'; cpro_cbg='#FFFFFF'; cpro_ctitle='#215670'; cpro_cdesc='#444444'; cpro_curl='#808080'; cpro_cflush='#e10900'; cpro_uap=1; cpro_cad=1; cpro_channel=4; </script><script src="http://cpro.baidu.com/cpro/ui/cp.js" type="text/javascript"></script>
-

aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
  http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.1.xsd ">
<bean id="dataSource"
  class="org.apache.commons.dbcp.BasicDataSource">
  <property name="driverClassName">
   <value>oracle.jdbc.driver.OracleDriver</value>
  </property>
  <property name="url">
   <value>jdbc:oracle:thin:@10.10.10.10:1521:demo</value>
  </property>
  <property name="username">
   <value>demo</value>
  </property>
  <property name="password">
   <value>demo</value>
  </property>
</bean>
<bean id="sessionFactory"
  class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
  <property name="dataSource">
   <ref bean="dataSource" />
  </property>
  <property name="hibernateProperties">
   <props>
    <prop key="hibernate.dialect">
     org.hibernate.dialect.OracleDialect
    </prop>
    <prop key="hibernate.connection.pool_size">5</prop>
    <prop key="hibernate.show_sql">true</prop>
    <prop key="cache.provider_class">
     org.hibernate.cache.OSCacheProvider
    </prop>
    <prop key="cache.use_query_cache">true</prop>
    <prop key="cglib.use_reflection_optimizer">false</prop>
   </props>
  </property>
  <property name="mappingDirectoryLocations">
   <list><!-- 这里指定了hibernate的映射目录 -->
    <value>classpath:/com/fifthlab/demo/pojo</value>
   </list>
  </property>
</bean>

<bean id="transactionManager"
  class="org.springframework.orm.hibernate3.HibernateTransactionManager">
  <property name="sessionFactory" ref="sessionFactory" />
</bean>

<!-- Transaction template for Managers -->
<bean id="txProxyTemplate" abstract="true"
  class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
  <property name="transactionManager" ref="transactionManager" />
  <property name="transactionAttributes">
   <props>
    <prop key="save*">PROPAGATION_REQUIRED</prop>
    <prop key="add*">PROPAGATION_REQUIRED</prop>
    <prop key="delete*">PROPAGATION_REQUIRED</prop>
    <prop key="update*">PROPAGATION_REQUIRED</prop>
    <prop key="relation*">PROPAGATION_REQUIRED</prop>
    <prop key="disconnect*">PROPAGATION_REQUIRED</prop>
    <prop key="assign*">PROPAGATION_REQUIRED</prop>
    <prop key="unassign*">PROPAGATION_REQUIRED</prop>
    <prop key="*">PROPAGATION_SUPPORTS</prop>
   </props>
  </property>
</bean>

<!-- XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX acegi part begin XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -->
<!-- ======================== FILTER CHAIN ======================= -->
<!--  if you wish to use channel security, add "channelProcessingFilter," in front
  of "httpSessionContextIntegrationFilter" in the list below -->
<bean id="filterChainProxy"
  class="org.acegisecurity.util.FilterChainProxy">
  <property name="filterInvocationDefinitionSource">
   <value>
    CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
    PATTERN_TYPE_APACHE_ANT
    /**/*.jsf=httpSessionContextIntegrationFilter,captchaValidationProcessingFilter ,authenticationProcessingFilter,anonymousProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor
   </value>
  </property>
</bean>

<bean id="httpSessionContextIntegrationFilter"
  class="org.acegisecurity.context.HttpSessionContextIntegrationFilter">
  <property name="context">
   <value><!-- 此处修复了Acegi和jCaptcha不能兼容的一个bug,在后面的版本中应该修复了 -->
    com.fifthlab.demo.dao.authentication.FixedCaptchaSecurityContextImpl
   </value>
  </property>
</bean>

<bean id="authenticationManager"
  class="org.acegisecurity.providers.ProviderManager">
  <property name="providers">
   <list>
    <ref local="daoAuthenticationProvider" />
   </list>
  </property>
</bean>

<bean id="daoAuthenticationProvider"
  class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
  <property name="userDetailsService">
   <ref local="hibernate3Authentication" />
  </property>
</bean>

<bean id="loggerListener"
  class="org.acegisecurity.event.authentication.LoggerListener" />

<bean id="authenticationProcessingFilter"
  class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
  <property name="authenticationManager">
   <ref bean="authenticationManager" />
  </property>
  <property name="authenticationFailureUrl">
   <value>/login.jsf </value>
  </property>
  <property name="defaultTargetUrl">
   <value>/login.jsf </value>
</property>
  <property name="filterProcessesUrl">
   <value>/j_acegi_security_check</value>
  </property>
</bean>
<bean id="exceptionTranslationFilter"
  class="org.acegisecurity.ui.ExceptionTranslationFilter">
  <property name="authenticationEntryPoint">
   <ref local="authenticationProcessingFilterEntryPoint" />
  </property>
</bean>

<bean id="authenticationProcessingFilterEntryPoint"
  class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">
  <property name="loginFormUrl">
   <value>/login.jsf </value>
  </property>
  <property name="forceHttps">
   <value>false</value>
  </property>
</bean>

<bean id="filterInvocationInterceptor"
  class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
  <property name="authenticationManager">
   <ref bean="authenticationManager" />
  </property>
  <property name="accessDecisionManager">
   <ref local="httpRequestAccessDecisionManager" />
  </property>
  <property name="observeOncePerRequest">
   <value>true</value>
  </property>
  <property name="objectDefinitionSource">
   <value>
    CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
    PATTERN_TYPE_APACHE_ANT
    /login.jsp =ROLE_ANONYMOUS
    /success.jsp =ROLE_USER
   </value>
  </property>
</bean>

<!-- 用来验证用户名密码是否相符,并赋予相应的角色 -->
<bean id="hibernate3Authentication"
  class="com.fifthlab.demo.dao.authentication.Hibernate3Authentication ">
  <property name="sessionFactory">
   <ref local="sessionFactory" />
  </property>
</bean>

<bean id="anonymousProcessingFilter"
  class="org.acegisecurity.providers.anonymous.AnonymousProcessingFilter">
  <property name="key">
   <value>foobar</value>
  </property>
  <property name="userAttribute">
   <value>anonymousUser,ROLE_ANONYMOUS</value>
  </property>
</bean>

<bean id="httpRequestAccessDecisionManager"
  class="org.acegisecurity.vote.AffirmativeBased">
  <property name="allowIfAllAbstainDecisions">
   <value>false</value>
  </property>
  <property name="decisionVoters">
   <list>
    <ref bean="roleVoter" />
   </list>
  </property>
</bean>

<bean id="roleVoter" class="org.acegisecurity.vote.RoleVoter" />
<!-- 下面开始添加 jcaptcha  -->
<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.fifthlab.demo.dao.authentication.JCaptchaServiceProxyImpl ">
  <property name="jcaptchaService" ref="jcaptchaService" />
</bean>
<bean id="jcaptchaService"
  class="com.octo.captcha.service.image.DefaultManageableImageCaptchaService" />
<!-- XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX acegi part end XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -->

</beans>
    先解释一下上面applicationContext.xml中红色的部分是jCaptcha的一个filter,必须放在第二个位置,后面的是 acegi的filter,也就是说,要先验证图片验证码是否正确,再让acegi来验证用户名和密码。蓝色的部分是需要写的几个代码,其中有一个修复 bug的地方,如果不添加那个bean,在运行的时候就会报Cast转型的错误。下面列一下蓝色部分的代码:
FixedCaptchaSecurityContextImpl:
import org.acegisecurity.captcha.CaptchaSecurityContextImpl;
public class FixedCaptchaSecurityContextImpl extends CaptchaSecurityContextImpl {
public int hashCode() {

  if (getAuthentication() == null) {
   return (int) System.currentTimeMillis();
  } else {
   return this.getAuthentication().hashCode();
  }
}

}
Hibernate3Authentication:
import java.util.ArrayList;
import java.util.List;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.GrantedAuthorityImpl;
import org.acegisecurity.userdetails.UserDetails;
import org.acegisecurity.userdetails.UserDetailsService;
import org.acegisecurity.userdetails.UsernameNotFoundException;
import org.hibernate.Criteria;
import org.hibernate.criterion.Expression;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import com.fifthlab.demo.pojo.Roletest;
import com.fifthlab.demo.pojo.Usertest;
public class Hibernate3Authentication extends HibernateDaoSupport implements UserDetailsService {
public UserDetails loadUserByUsername(final String username)
{
  Criteria criteria = getHibernateTemplate().getSessionFactory().getCurrentSession().createCriteria(Usertest.class);
  criteria.add(Expression.eq(Usertest.PROP_USERNAME, username));
  List users = criteria.list();
  if (users.size() == 0)
  {
   throw new UsernameNotFoundException("User not found");
  }
  Usertest user = (Usertest) users.get(0);
  // get User roles of this user
  List<Roletest> userRoles = new ArrayList<Roletest>();
  userRoles.add(user.getRoletest());
  GrantedAuthority[] dbAuths = new GrantedAuthority[userRoles.size()];
  if (userRoles.size() == 0)
  {
   throw new U
sernameNotFoundException("User has no GrantedAuthority");
  }
  // grant authority to user
  String roleName = null;
  Roletest role = null;
  for (int i = 0; i < userRoles.size(); i++)
  {
   role = (Roletest) userRoles.get(i);
   if (null != role)
   {
    roleName = role.getRolename();
    dbAuths = new GrantedAuthorityImpl(roleName);   
   }
  }
  
  user.setAuthorities(dbAuths);
  
  return user;
}
}
JCaptchaServiceProxyImpl:
import org.acegisecurity.captcha.CaptchaServiceProxy;
import com.octo.captcha.service.image.ImageCaptchaService;
import com.octo.captcha.service.CaptchaServiceException;
public class JCaptchaServiceProxyImpl implements CaptchaServiceProxy {
   
    private ImageCaptchaService jcaptchaService;
  
    public boolean validateReponseForId(String id, Object response) {
  
      try {
       boolean result = jcaptchaService.validateResponseForID(id, response);
       //System.out.println("id:"+id+"\nresponse:"+response+"\nresult:"+result);
       return result;
  
      } catch (CaptchaServiceException cse) {
        //fixes known bug in JCaptcha
       cse.printStackTrace();
        return false;
      }
    }
  
    public void setJcaptchaService(ImageCaptchaService jcaptchaService) {
      this.jcaptchaService = jcaptchaService;
    }
  }
    接下来是简单的登录页面login.jsp和登录成功后的跳转页面success.jsp:
login.jsp:
<%@ page language="Java" c%>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<%@ taglib uri="https://ajax4jsf.dev.java.net/ajax" prefix="a4j"%>
<f:view>
<html>
<head>
<title>hello</title>
</head>
<META HTTP-EQUIV="PRAGMA" C>
<META HTTP-EQUIV="Pragma" C>
<META HTTP-EQUIV="Expires" C>
<body>

<h:form id="form1">
  <h:panelGrid columns="1">
   <h:panelGroup>
    <h:outputLabel value="username:" for="username" />
    <h:inputText id="username" value="#{loginBean.userName}" />
   </h:panelGroup>
   <h:panelGroup>
    <h:outputLabel value="password:" for="password" />
    <h:inputSecret id="password" value="#{loginBean.password}" />
   </h:panelGroup>
   <h:panelGroup>
    <h:outputLabel value="verifying code:" for="verifyingCode" />
    <h:inputText id="verifyingCode" value="#{loginBean.verifyingCode}" />
    <a4j:mediaOutput element="img" cacheable="false" session="false"
        createC id="showPic"
        mimeType="image/jpeg" />
    <a4j:commandLink reRender="showPic" requestDelay="40" >
     <h:outputText value="refresh" />
    </a4j:commandLink>
   </h:panelGroup>
   <h:panelGroup>
    <h:commandButton id="commandButton1" value="Submit"
     action="#{loginBean.authenticate}" />
   </h:panelGroup>
  </h:panelGrid>
</h:form>

</body>
</html>
</f:view>

    其中红色部分是应用了Ajax4jsf这个框架的两个标签,<a4j:mediaOutput> 是表示输出一个媒体,这里我选择的是输出图片,它会异步的产生图片,而不必 和页面载入时同步取图片。而<a4j:commandLink reRender="showPic"> 则是在看不清图片的情况下通过异步的方式刷新上面那个<a4j:mediaOutput> 的图片。
    success.jsp的页面很简单,就是显示一个“Welcome here”的字样,因此不列出来了。
    然后我们看一下页面中用到的backing bean的代码:
LoginBean:
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpSession;
import org.acegisecurity.Authentication;
import org.acegisecurity.AuthenticationException;
import org.acegisecurity.AuthenticationManager;
import org.acegisecurity.context.SecurityContext;
import org.acegisecurity.context.SecurityContextHolder;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import com.fifthlab.demo.dao.authentication.JCaptchaServiceProxyImpl;
public class LoginBean extends HibernateDaoSupport {
private static final long serialVersionUID = 1L;
private String userName;
private String password;
private String verifyingCode;
private AuthenticationManager authenticationManager;
private JCaptchaServiceProxyImpl captchaService;
/**
  * @return 返回用户输入的验证码
  */
public String getVerifyingCode()
{
  return this.verifyingCode;
}

/**
  * @param verifyingCode 设置图片验证码
  */
public void setVerifyingCode(String verifyingCode)
{
  this.verifyingCode = verifyingCode;
}

/**
  * @return 返回captchaService来验证图片验证码
  */
public JCaptchaServiceProxyImpl getCaptchaService()
{
  return this.captchaService;
}

/**
  * @param captchaService 设置图片验证码服务
  */
public void setCaptchaService(JCaptchaServiceProxyImpl captchaService)
{
  this.captchaService = captchaService;
}

/**
  * @return 返回密码
  */
public String getPassword()
{
  return password;
}
/**
  * @param password 设置密码
  *            
  */
public void setPassword(String password)
{
  this.password = password;
}
/**
  * @return 返回用户名
  */
public String getUserName()
{
  return userName;
}
/**
  * @pa
ram userName 设置用户名
  *            
  */
public void setUserName(String userName)
{
  this.userName = userName;
}
/**
  * @return 返回验证管理器
  */
public AuthenticationManager getAuthenticationManager()
{
  return authenticationManager;
}
/**
  * @param authenticationManager 设置验证管理器
  *            
  */
public void setAuthenticationManager(AuthenticationManager authenticationManager)
{
  this.authenticationManager = authenticationManager;
}

public String authenticate()
{
  try
  {
   String sessionid = ((HttpSession)FacesContext.getCurrentInstance()
           .getExternalContext()
           .getSession(false)).getId();
   boolean captchaResult = getCaptchaService().validateReponseForId(sessionid, getVerifyingCode());//验证图片验证码
     UsernamePasswordAuthenticationToken authReq = new UsernamePasswordAuthenticationToken(
     getUserName(), getPassword());
   //验证用户名和密码
   Authentication auth = getAuthenticationManager().authenticate(authReq);
   String result = "failure";
   if(auth.isAuthenticated() == true && captchaResult)
   {//如果图片验证码和帐户全部验证通过
    result = "succeed";
    //把验证信息保存的上下文中
    SecurityContext secCtx = SecurityContextHolder.getContext();
    secCtx.setAuthentication(auth);
   }
      
   return result;
  }
  catch(AuthenticationException e)
  {
   e.printStackTrace();
   return "failure";
  }
}
}

CaptchaImageBean:
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import com.octo.captcha.service.image.ImageCaptchaService;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
public class CaptchaImageBean {
static final long serialVersionUID = 1L;
private ImageCaptchaService jcaptchaService;

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

public void paint(OutputStream out, Object data) throws IOException
{
  byte[] captchaChallengeAsJpeg = null;
  ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();
  
  HttpServletRequest request = (HttpServletRequest)FacesContext.getCurrentInstance()
        .getExternalContext().getRequest();
  
  String captchaId = ((HttpSession)FacesContext.getCurrentInstance()
    .getExternalContext()
    .getSession(false)).getId();
  
  BufferedImage challenge = jcaptchaService.getImageChallengeForID(
    captchaId, request.getLocale());
  JPEGImageEncoder jpegEncoder = JPEGCodec.createJPEGEncoder(jpegOutputStream);
  jpegEncoder.encode(challenge);
  captchaChallengeAsJpeg = jpegOutputStream.toByteArray();
  
  jpegOutputStream.close();
  out.write(captchaChallengeAsJpeg);
  out.flush();
  out.close();
}
}
    最后当然是配置faces-config.xml了,里面配置了和Spring的整合、导航、managed bean等等:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE faces-config PUBLIC "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN" "http://java.sun.com/dtd/web-facesconfig_1_1.dtd">

<faces-config>
<application>
  <variable-resolver>
   org.springframework.web.jsf.DelegatingVariableResolver
  </variable-resolver>
</application>
<managed-bean>
  <managed-bean-name>loginBean</managed-bean-name>
  <managed-bean-class>com.fifthlab.demo.backingbean.LoginBean</managed-bean-class>
  <managed-bean-scope>request</managed-bean-scope>
  <managed-property>
   <property-name>authenticationManager</property-name>
   <value>#{authenticationManager}</value>
  </managed-property>
  <managed-property>
   <property-name>captchaService</property-name>
   <value>#{captchaService}</value>
  </managed-property>
</managed-bean>

<managed-bean>
  <managed-bean-name>captchaImageBean</managed-bean-name>
  <managed-bean-class>com.fifthlab.demo.backingbean.CaptchaImageBean</managed-bean-class>
  <managed-bean-scope>request</managed-bean-scope>
  <managed-property>
   <property-name>jcaptchaService</property-name>
   <value>#{jcaptchaService}</value>
  </managed-property>
</managed-bean>

<navigation-rule>
  <from-view-id>/login.jsp</from-view-id>
  <navigation-case>
   <from-outcome>succeed</from-outcome>
   <to-view-id>/success.jsp</to-view-id>
  </navigation-case>
  <navigation-case>
   <from-outcome>failure</from-outcome>
   <to-view-id>/login.jsp</to-view-id>
  </navigation-case>
</navigation-rule>
</faces-config>