浏览 2727 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2008-12-06
最后修改:2009-01-08
新的配置方式: <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 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2009-01-08
最近正在整理以前的安全系统, 没有用过Spring Security, 但是想研究一下; 请教lz一个问题: Spring Security非得绑定Springframework吗?
|
|
返回顶楼 | |
发表时间:2009-01-08
回复ls,一定的
|
|
返回顶楼 | |