`
fangshun
  • 浏览: 8012 次
  • 性别: Icon_minigender_1
  • 来自: 西安
社区版块
存档分类
最新评论

myfaces1.x,seam1.2.1和spring security 2.0(acegi)的集成

阅读更多
acegi升级为spring security2.0后配置有很大不同,按照老的配置方式需要更改很多包路径,以及属性名,这需要在源代码中查找,如果配置好是没有问题的。新的配置是基于老的方式并进行了简化,就直接给出我的配置作为参考:
新的配置方式:
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:security="http://www.springframework.org/schema/security"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
              http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.4.xsd">  

	<security:http auto-config="true" access-denied-page="/login.faces">
		<security:intercept-url pattern="/jsp/*/yourpath" access="ROLE_COMMISSAR, ROLE_DRAFTOFFICE, ROLE_TRANSACT, ROLE_DRAFTSUPER, ROLE_URGER"/>
		<security:intercept-url pattern="/jsp/*/yourpath" access="ROLE_LETTERPUBLIC,ROLE_LETTERTRANSACT,ROLE_LETTERTASTER,ROLE_LETTERPROCESS"/>
		<security:intercept-url pattern="/jsp/*/yourpath" access="ROLE_POPULARSUBMIT,ROLE_POPULARPROCESS"/>
		<security:intercept-url pattern="/**/*.gif" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
		<security:intercept-url pattern="/**/*.gif" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
		<security:intercept-url pattern="/**/*.jpg" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
		<security:intercept-url pattern="/**/*.css" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
		<security:intercept-url pattern="/login.faces" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
		<security:intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" />
		<security:form-login 
			default-target-url="/"
			always-use-default-target="true"
			login-page="/login.faces"
			login-processing-url="/j_spring_security_check"
			authentication-failure-url="/login.faces" 
			/>
		<security:anonymous key="doesNotMatter" username="anonymousUser"/>
		 <security:concurrent-session-control 
			max-sessions="1" 
			exception-if-maximum-exceeded="false"
			expired-url="/login.faces"/>
		<security:logout logout-url="/j_spring_security_logout" logout-success-url="/login.faces" />
	</security:http>
	
	<security:authentication-provider>
		<security:jdbc-user-service 
			data-source-ref="dataSource" 
			users-by-username-query="SELECT USER_, PASSWORD_, SIGN_ FROM ORM_USER WHERE USER_= ?"
			authorities-by-username-query="select user0_.USER_ as col_0_0_, role2_.VALUE_ as col_1_0_ from ORM_USER user0_  inner join ORM_USER_ROLE roles1_ on user0_.ID_=roles1_.USERID_ inner join ORM_ROLE role2_ on roles1_.ROLEID_=role2_.ID_ where user0_.USER_=?"
			cache-ref="userCache"	
			/>
	</security:authentication-provider>
	
	<bean id="userCache" class="org.springframework.security.providers.dao.cache.EhCacheBasedUserCache">
		<property name="cache"><ref local="userCacheBackend"/></property>
	</bean>	
	
	<bean id="userCacheBackend" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
		<property name="cacheManager"> <ref local="cacheManager"/> </property>
		<property name="cacheName"> <value>userCache</value> </property>
	</bean>
	
	<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"/>
	
	<!-- This bean is optional; it isn't used by any other bean as it only listens and logs -->
	<bean id="loggerListener" class="org.springframework.security.event.authentication.LoggerListener" />
	
	<!-- <bean id="customAuthenticationFilter" class="**.authorization.CustomAuthenticationFilter">
		<security:custom-filter position="AUTHENTICATION_PROCESSING_FILTER"/>
	</bean>  使用自定义的过滤器,参考spring security中不同的自定义位置名称--> 
	
</beans>


jsf集成:

jsf跳转机制使用的是redirect,所以登录的信息就不能很好的传递给acegi,根据myfaces wiki提供的方式:创建登录使用的loginBean,注意不要使用seam的@Name注册为seam组件,直接使用jsf的managed-bean机制注册成backingbean
	public String login() throws IOException, ServletException
    {
        ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();
        
        RequestDispatcher dispatcher = ((ServletRequest) context.getRequest())
                 .getRequestDispatcher("/j_spring_security_check");
 
        dispatcher.forward((ServletRequest) context.getRequest(),
                (ServletResponse) context.getResponse());
        FacesContext.getCurrentInstance().responseComplete();
        // It's OK to return null here because Faces is just going to exit.
        logger.debug("=================================================" + 
        		((HttpServletRequest)context.getRequest()).getSession().getId());
        HttpSession session = ((HttpServletRequest)context.getRequest()).getSession();
//        session.setAttribute(LOGIN_PROCESS, new Boolean(true));
       //这是调整seam的集成部分
		ContextControl.instance().begin(session);
		//createAuthData(session, user);
        return null;
    }
	

	
	public String logout() throws IOException, ServletException
    {
        ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();
 
        RequestDispatcher dispatcher = ((ServletRequest) context.getRequest())
                 .getRequestDispatcher("/j_spring_security_logout");
 
        dispatcher.forward((ServletRequest) context.getRequest(),
                (ServletResponse) context.getResponse());

        FacesContext.getCurrentInstance().responseComplete();
        // It's OK to return null here because Faces is just going to exit.
        logger.debug("=================================================" + 
        		((HttpServletRequest)context.getRequest()).getSession().getId());       
        HttpSession session = ((HttpServletRequest)context.getRequest()).getSession();
     //这是调整seam的集成部分
    	ContextControl.instance().begin(session);
        return null;
    }

jsf页面的做法
<t:inputText id="j_username" forceId="true" styleClass="form1" size="20" value="#{loginBean.userName}"></t:inputText>
<t:inputSecret id="j_password" forceId="true" styleClass="form1" size="20" value="#{loginBean.password}"
<h:commandButton value="登录" action="#{loginBean.login}"></h:commandButton>


seam的集成:
因为在登录过程中,acegi注销掉了上一个session,创建了一个新的session,那么SeamListener这个session监听器就会执行sessionDestroyed和sessionCreated,但是seam并不认为你是真正销毁了所有的上下文包括request和application,我认为这是seam为了在页面过期的环境中使用,因为它的原则是由seam的Seam.invalidateSession()来处理session的销毁(事实上根本就没有销毁session而是给出了销毁的标记,也许这样就可以由它的内部解决所有上下文的管理)。那么就会产生异常,同样在这一次请求中seam的阶段监听也会产生异常,因为Conversation绑定的session仍然是已经过期的session。我的做法很傻,hack了!

一:自定义SeamListener
	@Override
	public void sessionCreated(HttpSessionEvent event) {
		// TODO Auto-generated method stub
		super.sessionCreated(event);
	}
	
	@Override
	public void sessionDestroyed(HttpSessionEvent event) {
		// TODO Auto-generated method stub
//		event.getSession().getAttribute("org.jboss.seam.sessionInvalid");
		try {			
			super.sessionDestroyed(event);
		} catch (IllegalStateException e) {
			// TODO: handle exception
			Seam.invalidateSession();
			HttpSession session = event.getSession();
			ContextControl.instance().end(session.getServletContext(), new ServletSessionImpl(session));
		}
	}


二 创建自定义的seam上下文控制类,直接操作各个上下文,对于session销毁和创建手动去清理或者创建其他各上下文实例。因为各个上下文的操作都是protect,所以只有将类建在它的包下了!
package org.jboss.seam.contexts;

import java.util.Set;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.seam.Component;
import org.jboss.seam.ScopeType;
import org.jboss.seam.core.ConversationEntries;
import org.jboss.seam.servlet.ServletSessionImpl;

public class ContextControl {
	private static final Log log = LogFactory.getLog(ContextControl.class);
	
	private static final ContextControl contextControl = new ContextControl();
	
	public static ContextControl instance() {
		return contextControl;
	}
	
	public void begin(HttpSession session) {
	      boolean applicationContextActive = Contexts.isApplicationContextActive();
	      boolean eventContextActive = Contexts.isEventContextActive();
	      boolean conversationContextActive = Contexts.isConversationContextActive();
	      if ( !applicationContextActive )
	      {
	         Context tempApplicationContext = new WebApplicationContext(session.getServletContext());
	         Contexts.applicationContext.set(tempApplicationContext);
	      }
	      Context tempEventContext = null;
	      if ( !eventContextActive )
	      {
	         tempEventContext = new MapContext(ScopeType.EVENT);
	         Contexts.eventContext.set(tempEventContext);
	      }
	      Context tempConversationContext = null;
	      if ( !conversationContextActive )
	      {
	         tempConversationContext = new MapContext(ScopeType.CONVERSATION);
	         Contexts.conversationContext.set(tempConversationContext);
	      }

	      Context tempSessionContext = new WebSessionContext(new ServletSessionImpl(session));
	      Contexts.sessionContext.set(tempSessionContext);		
	      
	      //instantiate all session-scoped @Startup components
	      for ( String name : Contexts.getApplicationContext().getNames() )
	      {
	         Object object = Contexts.getApplicationContext().get(name);
	         if ( object!=null && (object instanceof Component) ) 
	         {
	            Component component = (Component) object;
	            if ( component.isStartup() && component.getScope() == ScopeType.SESSION )
	            {
	               startup(component);
	            }
	         }
	      }	      
	}
	
	public void end(ServletContext servletContext, ContextAdaptor session) {
	      
	      Context tempApplicationContext = new WebApplicationContext(servletContext);
	      Contexts.applicationContext.set(tempApplicationContext);

	      //this is used just as a place to stick the ConversationManager
	      Context tempEventContext = new MapContext(ScopeType.EVENT);
	      Contexts.eventContext.set(tempEventContext);

	      //this is used (a) for destroying session-scoped components
	      //and is also used (b) by the ConversationManager
	      Context tempSessionContext = new WebSessionContext(session);
	      Contexts.sessionContext.set(tempSessionContext);

	      Set<String> conversationIds = ConversationEntries.instance().getConversationIds();
	      log.debug("destroying conversation contexts: " + conversationIds);
	      for (String conversationId: conversationIds)
	      {
	         Lifecycle.destroyConversationContext(session, conversationId);
	      }
	      
	      //we need some conversation-scope components for destroying
	      //the session context...
	      Context tempConversationContext = new MapContext(ScopeType.CONVERSATION);
	      Contexts.conversationContext.set(tempConversationContext);

	      log.debug("destroying session context");
	      Contexts.destroy(tempSessionContext);
	      Contexts.sessionContext.set(null);
	      
	      Contexts.destroy(tempConversationContext);
	      Contexts.conversationContext.set(null);

	      Contexts.destroy(tempEventContext);
	      Contexts.eventContext.set(null);

	      Contexts.applicationContext.set(null);		
	}
	
	   private static void startup(Component component)
	   {
	      if ( component.isStartup() )
	      {
	         for ( String dependency: component.getDependencies() )
	         {
	            Component dependentComponent = Component.forName(dependency);
	            if (dependentComponent!=null)
	            {
	               startup( dependentComponent );
	            }
	         }
	      }

	      if ( !component.getScope().getContext().isSet( component.getName() ) ) 
	      {
	         log.info("starting up: " + component.getName());
	         component.newInstance();
	      }
	   }
}


这些只是我的做法!
注意的地方:
websphere 6.1.0.3以上版本默认对于找不到资源的url路径直接过滤到错误页面,这样spring的/j_spring_security_check是访问不到的,需要参考http://topic.csdn.net/u/20080620/14/9c05c7d7-a6a0-4646-95b2-4bdadcb1002c.html
分享到:
评论
2 楼 fangshun 2009-01-08  
回复ls,一定的
1 楼 Dony 2009-01-08  
最近正在整理以前的安全系统, 没有用过Spring Security, 但是想研究一下; 请教lz一个问题: Spring Security非得绑定Springframework吗?

相关推荐

    myfaces-all.jar.zip

    《MyFaces 全集:深入理解myfaces-all.jar.zip》 ...理解MyFaces的核心概念和组件,以及如何有效地集成和使用,对于Java Web开发者来说至关重要。同时,尊重并遵守开源许可证的规定,也是每个开发者应有的责任。

    Apache MyFaces Scripting.zip

    在"Apache MyFaces Scripting.zip"的文件中,你可能会找到示例代码、教程文档,或者用于演示如何在MyFaces中集成和使用脚本的项目。通过深入研究这些内容,你可以进一步了解如何在实际项目中利用MyFaces的脚本功能...

    Apache MyFaces Core.zip

    开发者可以根据项目需求选择合适的版本,如MyFaces Core 2.x或3.x。 总结来说,Apache MyFaces Core是构建JavaEE Web应用的强大工具,它为开发者提供了丰富的组件库、灵活的扩展机制以及与其他JavaEE技术的紧密集成...

    常用手册 JSF及Myfaces帮助.CHM

    MyFaces以其灵活性、稳定性和高性能而受到开发者欢迎,可以与许多其他开源项目(如Tomcat、Struts、Hibernate等)无缝集成。 **CHM(Compiled Help Manual)**文件是一种Windows平台下的帮助文档格式,它是HTML文档...

    Apache MyFaces Trinidad.zip

    1. **组件库**:Trinidad包含了一套全面的UI组件,如按钮、输入字段、表格、树形结构、对话框等,这些组件都是可重用的,并且具有多种风格和主题,可以根据需求进行定制。 2. **数据模型**:Trinidad支持数据绑定,...

    JSF及Myfaces帮助.rar

    1. **灵活性**:MyFaces提供了更多的定制选项,开发者可以根据需求选择不同的组件库和渲染器。 2. **社区驱动**:MyFaces有一个活跃的开发者社区,这意味着不断有新的特性和改进被引入,问题能得到快速解决。 3. **...

    myfaces-core-2.0.1-bin.zip

    综上所述,`myfaces-core-2.0.1-bin.zip`包含了MyFaces JSF实现的核心组件,开发者可以通过这个压缩包快速地在项目中集成MyFaces,利用其丰富的功能和组件来构建高效、可维护的Web应用程序。在实际开发中,理解...

    com.springsource.org.apache.myfaces-1.1.5.jar

    jar包,官方版本,自测可用

    JSF与Shale开发用包

    aop.jar spring-beans.jar spring-context.jar spring-core.jar spring-dao.jar spring-hibernate.jar spring-jdbc.jar spring-mock.jar spring-orm.jar spring-remoting.jar spring-...

    myfaces-all-1.1.1.jar

    此外,随着技术的演进,更现代的MyFaces版本如2.x和3.x可能引入了更多功能和性能优化,对于新项目,选择较新的版本可能是更好的选择。 总之,myfaces-all-1.1.1.jar作为MyFaces框架的一个重要组成部分,它在Java ...

    JSF.rar_JSF_myfaces-all.j

    1. **JSF教程文档**:这些文档可能详细介绍了JSF的基础知识,如何创建和配置JSF项目,以及如何使用JSF的标签库。 2. **示例代码**:可能会有一些示例应用程序,展示JSF组件的用法,以及如何处理用户事件。 3. **...

    com.springsource.org.apache.myfaces.javax.faces-1.1.5.jar

    jar包,官方版本,自测可用

    com.springsource.org.apache.myfaces.javax.faces_1.2.2.jar

    jar包,官方版本,自测可用

    JSF及Myfaces帮助

    JSF及Myfaces帮助.CHM

    MyFaces 上下文参数详解(中、英文)

    一、`org.apache.myfaces.SERIALIZE_STATE_IN_SESSION` 此参数控制MyFaces是否将组件状态存储在会话中。默认值为`true`,意味着组件状态会在每个请求之间序列化并存储在用户的会话中。如果设置为`false`,状态将...

    myfaces的jar包,是官网最新的。

    MyFaces是JavaServer Faces(JSF) Web框架 (JSR 127)的一个实现。JavaServer(tm) Faces Web框架是一个新的实现MVC模式的规范.它可以与Struts框架相媲美甚至的一些特性与观念已经超过了Struts.【FacesIDE:Eclipse下的...

    jsf2.0源碼(myfaces2.0.4 api+impl)

    **JSF 2.0 源码解析:MyFaces 2.0.4 API + Impl** JavaServer Faces (JSF) 是一个用于构建企业级Web应用的Java框架,它提供了一种组件化的方式来创建用户界面。JSF 2.0是其一个重要版本,引入了许多新特性以提升...

    myfaces-1.1.5

    6. **CDI 集成**:MyFaces 可以与 Contexts and Dependency Injection (CDI) 框架集成,提供依赖注入和上下文管理功能。 7. **EL 表达式语言**:JSF 使用统一的 Expression Language (EL) 与模型数据进行交互,...

    myfaces-extensions-1.0.9.jar

    http://www.ibiblio.org/maven/myfaces/jars/ myfaces-extensions-1.0.9.jar

    myfaces+ajax4jsf+spring+jpa+chartCreate 配置备忘.part1

    myfaces+ajax4jsf+spring+jpa+chartCreate 配置备忘 完整eclipse项目源代码

Global site tag (gtag.js) - Google Analytics