文档库 最新最全的文档下载
当前位置:文档库 › Spring+Hibernate+JSF+Ajax4jsf+Acegi+jCaptcha

Spring+Hibernate+JSF+Ajax4jsf+Acegi+jCaptcha

Spring+Hibernate+JSF+Ajax4jsf+Acegi+jCaptcha
Spring+Hibernate+JSF+Ajax4jsf+Acegi+jCaptcha

带图片验证码的用户登录是一个系统中很常见的模块,在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的配置一下了:

xmlns="https://www.wendangku.net/doc/691517423.html,/xml/ns/javaee"

xmlns:web="https://www.wendangku.net/doc/691517423.html,/xml/ns/javaee/web-app_2_5.xsd"

xsi:schemaLocation="https://www.wendangku.net/doc/691517423.html,/xml/ns/javaee

https://www.wendangku.net/doc/691517423.html,/xml/ns/javaee/web-app_2_5.xsd"

id="WebApp_ID" version="2.5">

Demo

index.html

index.htm

index.jsp

contextConfigLocation

/WEB-INF/classes/applicationContext.xml

javax.faces.CONFIG_FILES

/WEB-INF/faces-config.xml

org.springframework.web.context.ContextLoaderListener

org.acegisecurity.ui.session.HttpSessionEventPublisher

com.sun.faces.config.ConfigureListener

OpenSessionInView

org.springframework.orm.hibernate3.support.OpenSessionInViewFilter

singleSession

true

OpenSessionInView

*.jsf

Acegi Filter Chain Proxy

org.acegisecurity.util.FilterToBeanProxy

targetClass

org.acegisecurity.util.FilterChainProxy

Acegi Filter Chain Proxy

/*

FORWARD

REQUEST

Ajax4jsf Filter

ajax4jsf

org.ajax4jsf.Filter

ajax4jsf

Faces Servlet

REQUEST

FORWARD

INCLUDE

Faces Servlet

javax.faces.webapp.FacesServlet

1

Faces Servlet

*.jsf

然后Spring的applicationContext.xml,在这里面你需要配置数据库连接、hibernate 的各种策略、Acegi安全设置、jCaptcha设置等等:

xmlns:xsi="https://www.wendangku.net/doc/691517423.html,/2001/XMLSchema-instance"

xmlns:aop="https://www.wendangku.net/doc/691517423.html,/schema/aop"

xsi:schemaLocation="https://www.wendangku.net/doc/691517423.html,/schema/beans

https://www.wendangku.net/doc/691517423.html,/schema/beans/spring-beans-2.0.xsd

https://www.wendangku.net/doc/691517423.html,/schema/aop

https://www.wendangku.net/doc/691517423.html,/schema/aop/spring-aop-2.1.xsd">

class="https://www.wendangku.net/doc/691517423.html,mons.dbcp.BasicDataSource">

oracle.jdbc.driver.OracleDriver

jdbc:oracle:thin:@10.10.10.10:1521:demo

demo

demo

class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">

org.hibernate.dialect.OracleDialect

5

true

org.hibernate.cache.OSCacheProvider

true

false

classpath:/com/fifthlab/demo/pojo

class="org.springframework.orm.hibernate3.HibernateTransactionManager">

class="org.springframework.transaction.interceptor.TransactionProxyFactoryBea n">

PROPAGATION_REQUIRED

PROPAGATION_REQUIRED

PROPAGATION_REQUIRED

PROPAGATION_REQUIRED

PROPAGATION_REQUIRED

PROPAGATION_REQUIRED

PROPAGATION_REQUIRED

PROPAGATION_REQUIRED

PROPAGATION_SUPPORTS

class="org.acegisecurity.util.FilterChainProxy">

CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON

PATTERN_TYPE_APACHE_ANT

/**/*.jsf=httpSessionContextIntegrationFilter,captchaValidationProcessingFi lter,authenticationProcessingFilter,anonymousProcessingFilter,exceptionTranslat ionFilter,filterInvocationInterceptor

class="org.acegisecurity.context.HttpSessionContextIntegrationFilter">

com.fifthlab.demo.dao.authentication.FixedCaptchaSecurityContextImpl

class="org.acegisecurity.providers.ProviderManager">

class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">

class="org.acegisecurity.event.authentication.LoggerListener" />

class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">

/login.jsf

/login.jsf

/j_acegi_security_check

class="org.acegisecurity.ui.ExceptionTranslationFilter">

class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">

/login.jsf

false

class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">

true

CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON

PATTERN_TYPE_APACHE_ANT

/login.jsp=ROLE_ANONYMOUS

/success.jsp=ROLE_USER

class="com.fifthlab.demo.dao.authentication.Hibernate3Authentication">

class="org.acegisecurity.providers.anonymous.AnonymousProcessingFilter">

foobar

anonymousUser,ROLE_ANONYMOUS

class="org.acegisecurity.vote.AffirmativeBased">

false

class="org.acegisecurity.captcha.CaptchaValidationProcessingFilter">

j_captcha_response

class="com.fifthlab.demo.dao.authentication.JCaptchaServiceProxyImpl">

class="com.octo.captcha.service.image.DefaultManageableImageCaptchaService" />

先解释一下上面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 https://www.wendangku.net/doc/691517423.html,erDetails;

import https://www.wendangku.net/doc/691517423.html,erDetailsService;

import https://www.wendangku.net/doc/691517423.html,ernameNotFoundException;

import org.hibernate.Criteria;

import org.hibernate.criterion.Expression;

import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.fifthlab.demo.pojo.Roletest;

import https://www.wendangku.net/doc/691517423.html,ertest;

public class Hibernate3Authentication extends HibernateDaoSupport implements UserDetailsService {

public UserDetails loadUserByUsername(final String username)

{

Criteria criteria =

getHibernateTemplate().getSessionFactory().getCurrentSession().createCriteria(U sertest.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 userRoles = new ArrayList();

userRoles.add(user.getRoletest());

GrantedAuthority[] dbAuths = new GrantedAuthority[userRoles.size()];

if (userRoles.size() == 0)

{

throw new UsernameNotFoundException("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[i] = 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" contentType="text/html;charset=utf-8"%>

<%@ taglib uri="https://www.wendangku.net/doc/691517423.html,/jsf/html" prefix="h"%>

<%@ taglib uri="https://www.wendangku.net/doc/691517423.html,/jsf/core" prefix="f"%>

<%@ taglib uri="https://https://www.wendangku.net/doc/691517423.html,/ajax" prefix="a4j"%>

hello

createContent="#{captchaImageBean.paint}" id="showPic"

mimeType="image/jpeg" />

action="#{loginBean.authenticate}" />

其中红色部分是应用了Ajax4jsf这个框架的两个标签, 是表示输出一个媒体,这里我选择的是输出图片,它会异步的产生图片,而不必和页面载入时同步取图片。而则是在看不清图片的情况下通过异步的方式刷新上面那个的图片。

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 https://www.wendangku.net/doc/691517423.html,ernamePasswordAuthenticationToken;

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;

}

/**

* @param userName 设置用户名

*

*/

public void setUserName(String userName)

{

https://www.wendangku.net/doc/691517423.html,erName = 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 等等:

org.springframework.web.jsf.DelegatingVariableResolver

loginBean

com.fifthlab.demo.backingbean.LoginBean

request

authenticationManager

#{authenticationManager}

captchaService

#{captchaService}

captchaImageBean

com.fifthlab.demo.backingbean.CaptchaImageBean

request

jcaptchaService

#{jcaptchaService}

/login.jsp

succeed

/success.jsp

failure

/login.jsp

大功告成!让我们来看一下演示吧:

填好帐户和验证码后,点击Submit,如果失败则还是该页不变,如果成功则跳转到:

不知道大家有没有实验成功?有任何问题可以给我留言!P.S. 需要的各种lib列表如下图:

相关文档