Spring+Hibernate+JSF+Ajax4jsf+Acegi+jCaptcha 做登录模块 博客分类: spring AcegiJSFSpringHibernateBean
带 图片验证码的用户登录是一个系统中很常见的模块,在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 [ 评论 ]
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>