LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 3361|回复: 7

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

[复制链接]
发表于 2009-2-18 13:37:49 | 显示全部楼层 |阅读模式
acegi升级为spring security2.0后配置有很大不同,按照老的配置方式需要更改很多包路径,以及属性名,这需要在源代码中查找,如果配置好是没有问题的。新的配置是基于老的方式并进行了简化,就直接给出我的配置作为参考:
新的配置方式:
  1. <beans xmlns="http://www.springframework.org/schema/beans"
  2.   xmlns:security="http://www.springframework.org/schema/security"
  3.   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4.   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
  5.               http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.4.xsd">  

  6.         <security:http auto-config="true" access-denied-page="/login.faces">
  7.                 <security:intercept-url pattern="/jsp/*/yourpath" access="ROLE_COMMISSAR, ROLE_DRAFTOFFICE, ROLE_TRANSACT, ROLE_DRAFTSUPER, ROLE_URGER"/>
  8.                 <security:intercept-url pattern="/jsp/*/yourpath" access="ROLE_LETTERPUBLIC,ROLE_LETTERTRANSACT,ROLE_LETTERTASTER,ROLE_LETTERPROCESS"/>
  9.                 <security:intercept-url pattern="/jsp/*/yourpath" access="ROLE_POPULARSUBMIT,ROLE_POPULARPROCESS"/>
  10.                 <security:intercept-url pattern="/**/*.gif" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
  11.                 <security:intercept-url pattern="/**/*.gif" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
  12.                 <security:intercept-url pattern="/**/*.jpg" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
  13.                 <security:intercept-url pattern="/**/*.css" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
  14.                 <security:intercept-url pattern="/login.faces" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
  15.                 <security:intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" />
  16.                 <security:form-login
  17.                         default-target-url="/"
  18.                         always-use-default-target="true"
  19.                         login-page="/login.faces"
  20.                         login-processing-url="/j_spring_security_check"
  21.                         authentication-failure-url="/login.faces"
  22.                         />
  23.                 <security:anonymous key="doesNotMatter" username="anonymousUser"/>
  24.                  <security:concurrent-session-control
  25.                         max-sessions="1"
  26.                         exception-if-maximum-exceeded="false"
  27.                         expired-url="/login.faces"/>
  28.                 <security:logout logout-url="/j_spring_security_logout" logout-success-url="/login.faces" />
  29.         </security:http>
  30.        
  31.         <security:authentication-provider>
  32.                 <security:jdbc-user-service
  33.                         data-source-ref="dataSource"
  34.                         users-by-username-query="SELECT USER_, PASSWORD_, SIGN_ FROM ORM_USER WHERE USER_= ?"
  35.                         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_=?"
  36.                         cache-ref="userCache"       
  37.                         />
  38.         </security:authentication-provider>
  39.        
  40.         <bean id="userCache" class="org.springframework.security.providers.dao.cache.EhCacheBasedUserCache">
  41.                 <property name="cache"><ref local="userCacheBackend"/></property>
  42.         </bean>       
  43.        
  44.         <bean id="userCacheBackend" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
  45.                 <property name="cacheManager"> <ref local="cacheManager"/> </property>
  46.                 <property name="cacheName"> <value>userCache</value> </property>
  47.         </bean>
  48.        
  49.         <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"/>
  50.        
  51.         <!-- This bean is optional; it isn't used by any other bean as it only listens and logs -->
  52.         <bean id="loggerListener" class="org.springframework.security.event.authentication.LoggerListener" />
  53.        
  54.         <!-- <bean id="customAuthenticationFilter" class="**.authorization.CustomAuthenticationFilter">
  55.                 <security:custom-filter position="AUTHENTICATION_PROCESSING_FILTER"/>
  56.         </bean>  使用自定义的过滤器,参考spring security中不同的自定义位置名称-->
  57.        
  58. </beans>
复制代码


jsf集成:

jsf跳转机制使用的是redirect,所以登录的信息就不能很好的传递给acegi,根据myfaces wiki提供的方式:创建登录使用的loginBean,注意不要使用seam的@Name注册为seam组件,直接使用jsf的managed-bean机制注册成backingbean
  1.         public String login() throws IOException, ServletException
  2.     {
  3.         ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();
  4.         
  5.         RequestDispatcher dispatcher = ((ServletRequest) context.getRequest())
  6.                  .getRequestDispatcher("/j_spring_security_check");

  7.         dispatcher.forward((ServletRequest) context.getRequest(),
  8.                 (ServletResponse) context.getResponse());
  9.         FacesContext.getCurrentInstance().responseComplete();
  10.         // It's OK to return null here because Faces is just going to exit.
  11.         logger.debug("=================================================" +
  12.                         ((HttpServletRequest)context.getRequest()).getSession().getId());
  13.         HttpSession session = ((HttpServletRequest)context.getRequest()).getSession();
  14. //        session.setAttribute(LOGIN_PROCESS, new Boolean(true));
  15.        //这是调整seam的集成部分
  16.                 ContextControl.instance().begin(session);
  17.                 //createAuthData(session, user);
  18.         return null;
  19.     }
  20.        

  21.        
  22.         public String logout() throws IOException, ServletException
  23.     {
  24.         ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();

  25.         RequestDispatcher dispatcher = ((ServletRequest) context.getRequest())
  26.                  .getRequestDispatcher("/j_spring_security_logout");

  27.         dispatcher.forward((ServletRequest) context.getRequest(),
  28.                 (ServletResponse) context.getResponse());

  29.         FacesContext.getCurrentInstance().responseComplete();
  30.         // It's OK to return null here because Faces is just going to exit.
  31.         logger.debug("=================================================" +
  32.                         ((HttpServletRequest)context.getRequest()).getSession().getId());      
  33.         HttpSession session = ((HttpServletRequest)context.getRequest()).getSession();
  34.      //这是调整seam的集成部分
  35.             ContextControl.instance().begin(session);
  36.         return null;
  37.     }
复制代码

jsf页面的做法
[code="xml"]<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>[/code]

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

一:自定义SeamListener
  1.         @Override
  2.         public void sessionCreated(HttpSessionEvent event) {
  3.                 // TODO Auto-generated method stub
  4.                 super.sessionCreated(event);
  5.         }
  6.        
  7.         @Override
  8.         public void sessionDestroyed(HttpSessionEvent event) {
  9.                 // TODO Auto-generated method stub
  10. //                event.getSession().getAttribute("org.jboss.seam.sessionInvalid");
  11.                 try {                       
  12.                         super.sessionDestroyed(event);
  13.                 } catch (IllegalStateException e) {
  14.                         // TODO: handle exception
  15.                         Seam.invalidateSession();
  16.                         HttpSession session = event.getSession();
  17.                         ContextControl.instance().end(session.getServletContext(), new ServletSessionImpl(session));
  18.                 }
  19.         }
复制代码


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

  2. import java.util.Set;

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

  5. import org.apache.commons.logging.Log;
  6. import org.apache.commons.logging.LogFactory;
  7. import org.jboss.seam.Component;
  8. import org.jboss.seam.ScopeType;
  9. import org.jboss.seam.core.ConversationEntries;
  10. import org.jboss.seam.servlet.ServletSessionImpl;

  11. public class ContextControl {
  12.         private static final Log log = LogFactory.getLog(ContextControl.class);
  13.        
  14.         private static final ContextControl contextControl = new ContextControl();
  15.        
  16.         public static ContextControl instance() {
  17.                 return contextControl;
  18.         }
  19.        
  20.         public void begin(HttpSession session) {
  21.               boolean applicationContextActive = Contexts.isApplicationContextActive();
  22.               boolean eventContextActive = Contexts.isEventContextActive();
  23.               boolean conversationContextActive = Contexts.isConversationContextActive();
  24.               if ( !applicationContextActive )
  25.               {
  26.                  Context tempApplicationContext = new WebApplicationContext(session.getServletContext());
  27.                  Contexts.applicationContext.set(tempApplicationContext);
  28.               }
  29.               Context tempEventContext = null;
  30.               if ( !eventContextActive )
  31.               {
  32.                  tempEventContext = new MapContext(ScopeType.EVENT);
  33.                  Contexts.eventContext.set(tempEventContext);
  34.               }
  35.               Context tempConversationContext = null;
  36.               if ( !conversationContextActive )
  37.               {
  38.                  tempConversationContext = new MapContext(ScopeType.CONVERSATION);
  39.                  Contexts.conversationContext.set(tempConversationContext);
  40.               }

  41.               Context tempSessionContext = new WebSessionContext(new ServletSessionImpl(session));
  42.               Contexts.sessionContext.set(tempSessionContext);               
  43.              
  44.               //instantiate all session-scoped @Startup components
  45.               for ( String name : Contexts.getApplicationContext().getNames() )
  46.               {
  47.                  Object object = Contexts.getApplicationContext().get(name);
  48.                  if ( object!=null && (object instanceof Component) )
  49.                  {
  50.                     Component component = (Component) object;
  51.                     if ( component.isStartup() && component.getScope() == ScopeType.SESSION )
  52.                     {
  53.                        startup(component);
  54.                     }
  55.                  }
  56.               }             
  57.         }
  58.        
  59.         public void end(ServletContext servletContext, ContextAdaptor session) {
  60.              
  61.               Context tempApplicationContext = new WebApplicationContext(servletContext);
  62.               Contexts.applicationContext.set(tempApplicationContext);

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

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

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

  81.               log.debug("destroying session context");
  82.               Contexts.destroy(tempSessionContext);
  83.               Contexts.sessionContext.set(null);
  84.              
  85.               Contexts.destroy(tempConversationContext);
  86.               Contexts.conversationContext.set(null);

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

  89.               Contexts.applicationContext.set(null);               
  90.         }
  91.        
  92.            private static void startup(Component component)
  93.            {
  94.               if ( component.isStartup() )
  95.               {
  96.                  for ( String dependency: component.getDependencies() )
  97.                  {
  98.                     Component dependentComponent = Component.forName(dependency);
  99.                     if (dependentComponent!=null)
  100.                     {
  101.                        startup( dependentComponent );
  102.                     }
  103.                  }
  104.               }

  105.               if ( !component.getScope().getContext().isSet( component.getName() ) )
  106.               {
  107.                  log.info("starting up: " + component.getName());
  108.                  component.newInstance();
  109.               }
  110.            }
  111. }
复制代码


这些只是我的做法!
注意的地方:
websphere 6.1.0.3以上版本默认对于找不到资源的url路径直接过滤到错误页面,这样spring的/j_spring_security_check是访问不到的,需要参考http://topic.csdn.net/u/20080620 ... 2-4bdadcb1002c.html
发表于 2009-2-18 16:15:21 | 显示全部楼层
这种配置好复杂,acegi因为是spring的因此一直没好好研究过。

其实安全框架就那样,简单的还行,复杂的还要自己实现。
但简单的还不如自己实现。

不过我奇怪JSF和SPRING一起用,好用吗?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2009-2-18 18:16:33 | 显示全部楼层
我们的项目就是一起用的,还行吧!acegi比较独立不会倾向于某个框架!
回复 支持 反对

使用道具 举报

发表于 2009-2-19 02:47:41 | 显示全部楼层
Post by fangshun;1949286
我们的项目就是一起用的,还行吧!acegi比较独立不会倾向于某个框架!


自从前年开始用guice就没关注过spring。Acegi也没怎么关注过。

想问一下版规:关于Java应用服务器的帖子,比如Glassfish之类的,是放在这个版块还是Linux服务器架设版块?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2009-2-19 14:10:12 | 显示全部楼层
Post by saharabear;1949467
自从前年开始用guice就没关注过spring。Acegi也没怎么关注过。

想问一下版规:关于Java应用服务器的帖子,比如Glassfish之类的,是放在这个版块还是Linux服务器架设版块?


放到java相关也是没有问题的!
回复 支持 反对

使用道具 举报

发表于 2009-2-19 14:32:08 | 显示全部楼层
Post by fangshun;1949644
放到java相关也是没有问题的!


OK,懂了。。

最近在搞Glassfish。。咱们版块够清凉的,也应该搞个东西上来了。。

主要是咱这版块在这网站上,定位不太准啊。
回复 支持 反对

使用道具 举报

发表于 2009-2-22 19:03:46 | 显示全部楼层
Post by saharabear;1949240
这种配置好复杂,acegi因为是spring的因此一直没好好研究过。

其实安全框架就那样,简单的还行,复杂的还要自己实现。
但简单的还不如自己实现。

不过我奇怪JSF和SPRING一起用,好用吗?

Spring 2.5 中JSF是first class支持的,在Spring WEB FLOW中,有spring faces的概念(没有单独打包),这个对jsf进行了深度集成(完全重写了)。不过感觉Spring web flow还是太复杂,一直没有好好看。
回复 支持 反对

使用道具 举报

发表于 2009-2-22 19:08:32 | 显示全部楼层
glassfish 现在可以说是 SUN 继java 和 Solaris后的第三个开源品牌,从它应用看,应该地位已经超过了 JBoss ,国外已经有几个电信厂商使用了glassfish。最近Sun 的中间件全部重新包装,贴上Glassfish标志,Glassfish 社区产品线已经不亚于 JBoss ,但主网站应该重新设计(openesb的网站都重新设计了),以提升形象。
从使用看,glassfish非常适合开发,启动比JBoss 5快 5倍以上。而且glassfish提供web管理界面,JBoss 5一次又一次跳票,最后连之前承诺的web管理界面功能也没有兑现(应该会在下一版本中提供,可能是GWT界面)。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表