CAS和Spring-shiro結合實現單點登出功能
阿新 • • 發佈:2018-12-22
CAS既然有單點登入功能,那麼自然有單點登出,意思就是其中一個子系統登出之後,其他所有系統都不能訪問。
下面我要說的是CAS和Spring-shiro結合實現單點登出功能結合實現的單點登出功能
這是應用系統web.xml配置,這裡要特別注意,登出校驗的配置一定要寫在Spring-shiro配置之前,否則會使單點登出不成功
<!-- 該過濾器用於實現單點登出功能,可選配置。 --> <listener> <listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class> </listener> <filter> <filter-name>CAS Single Sign Out Filter</filter-name> <filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class> <init-param> <param-name>casServerUrlPrefix</param-name> <param-value>http://localhost:8081/cas/</param-value> </init-param> </filter> <filter-mapping> <filter-name>CAS Single Sign Out Filter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- Apache Shiro --> <filter> <filter-name>shiroFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <init-param> <param-name>targetFilterLifecycle</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>shiroFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!--CAS SSO--> <filter> <filter-name>CAS Authentication Filter</filter-name> <filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class> <init-param> <param-name>casServerLoginUrl</param-name> <param-value>http://localhost:8081/cas/login</param-value> </init-param> <context-param> <param-name>renew</param-name> <param-value>false</param-value> </context-param> <init-param> <param-name>gateway</param-name> <param-value>false</param-value> </init-param> <init-param> <param-name>serverName</param-name> <param-value>http://localhost:8888</param-value> </init-param> <init-param> <param-name>ignorePattern</param-name> <param-value>/statistic/*|/static/*|/js/*|/img/*|/views/*|/css/*|webservice/*|/cas/changeCenter/*</param-value> </init-param> </filter> <filter> <filter-name>CAS Validation Filter</filter-name> <filter-class> org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter </filter-class> <init-param> <param-name>casServerUrlPrefix</param-name> <param-value>http://localhost:8081/cas</param-value> </init-param> <init-param> <param-name>serverName</param-name> <param-value>http://localhost:8888</param-value> </init-param> <init-param> <param-name>useSession</param-name> <param-value>true</param-value> </init-param> <init-param> <param-name>redirectAfterValidation</param-name> <param-value>true</param-value> </init-param> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter> <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name> <filter-class> org.jasig.cas.client.util.HttpServletRequestWrapperFilter </filter-class> </filter> <filter> <filter-name>CAS Assertion Thread Local Filter</filter-name> <filter-class> org.jasig.cas.client.util.AssertionThreadLocalFilter </filter-class> </filter> <filter-mapping> <filter-name>CAS Authentication Filter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter-mapping> <filter-name>CAS Validation Filter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter-mapping> <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter-mapping> <filter-name>CAS Assertion Thread Local Filter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
下面是Spring-shiro的配置檔案
<!-- Shiro許可權過濾過濾器定義 --> <bean name="shiroFilterChainDefinitions" class="java.lang.String"> <constructor-arg> <value> /img/** = anon /static/** = anon /userfiles/** = anon ${adminPath}/cas = cas ${adminPath}/cas/controlCenter/** = cas ${adminPath}/app/csWebappSso/** = user ${adminPath}/login = authc ${adminPath}/logout = logout ${adminPath}/** = user /act/editor/** = user /ReportServer/** = user </value> </constructor-arg> </bean> <bean id="logout" class="org.apache.shiro.web.filter.authc.LogoutFilter"> <property name="redirectUrl" value="${cas.logout.url}"/> </bean> <!-- 安全認證過濾器 --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager" /> <!-- <property name="loginUrl" value="${cas.server.url}/login?service=${cas.project.url}${adminPath}/cas"/> --> <property name="loginUrl" value="${adminPath}/login"/> <property name="successUrl" value="${adminPath}?login" /> <property name="filters"> <map> <entry key="cas" value-ref="casFilter" /> <entry key="authc" value-ref="formAuthenticationFilter" /> <entry key="logout" value-ref="logout"/> </map> </property> <property name="filterChainDefinitions"> <ref bean="shiroFilterChainDefinitions" /> </property> </bean> <!-- cas和shiro結合 --> <bean id="casRealm" class="com.wdim.modules.sys.security.CasLoginRealm"> <property name="casServerUrlPrefix" value="${cas.server.url}"></property> <property name="casService" value="${cas.project.url}${adminPath}/cas"></property> </bean> <!-- CAS認證過濾器 --> <bean id="casFilter" class="org.apache.shiro.cas.CasFilter"> <property name="failureUrl" value="${adminPath}/login" /> </bean> <!-- 定義Shiro安全管理配置 --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <!-- <property name="realm" ref="systemAuthorizingRealm" /> --> <property name="realms"> <list> <ref bean="casRealm"/> <ref bean="csSystemAuthorizingRealm"/> </list> </property> <property name="sessionManager" ref="sessionManager" /> <property name="cacheManager" ref="shiroCacheManager" /> </bean> <!-- 配置使用自定義認證器,可以實現多Realm認證,並且可以指定特定Realm處理特定型別的驗證 --> <bean id="authenticator" class="com.wdim.modules.sys.security.CustomizedModularRealmAuthenticator"> <!-- 配置認證策略,只要有一個Realm認證成功即可,並且返回所有認證成功資訊 --> <property name="authenticationStrategy"> <bean class="org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy"></bean> </property> </bean> <!-- 自定義會話管理配置 --> <bean id="sessionManager" class="com.wdim.common.security.shiro.session.SessionManager"> <property name="sessionDAO" ref="sessionDAO" /> <!-- 會話超時時間,單位:毫秒 --> <property name="globalSessionTimeout" value="${session.sessionTimeout}" /> <!-- 定時清理失效會話, 清理使用者直接關閉瀏覽器造成的孤立會話 --> <property name="sessionValidationInterval" value="${session.sessionTimeoutClean}" /> <!-- <property name="sessionValidationSchedulerEnabled" value="false"/> --> <property name="sessionValidationSchedulerEnabled" value="true" /> <property name="sessionIdCookie" ref="sessionIdCookie" /> <property name="sessionIdCookieEnabled" value="true" /> </bean> <!-- 指定本系統SESSIONID, 預設為: JSESSIONID 問題: 與SERVLET容器名衝突, 如JETTY, TOMCAT 等預設JSESSIONID, 當跳出SHIRO SERVLET時如ERROR-PAGE容器會為JSESSIONID重新分配值導致登入會話丟失! --> <bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie"> <constructor-arg name="name" value="jeesite.session.id" /> </bean> <!-- 自定義Session儲存容器 --> <!-- <bean id="sessionDAO" class="com.wdimmmon.security.shiro.session.JedisSessionDAO"> --> <!-- <property name="sessionIdGenerator" ref="idGen" /> --> <!-- <property name="sessionKeyPrefix" value="${redis.keyPrefix}_session_" /> --> <!-- </bean> --> <bean id="sessionDAO" class="com.wdim.common.security.shiro.session.CacheSessionDAO"> <property name="sessionIdGenerator" ref="idGen" /> <property name="activeSessionsCacheName" value="activeSessionsCache" /> <property name="cacheManager" ref="shiroCacheManager" /> </bean> <!-- 自定義系統快取管理器 --> <!-- <bean id="shiroCacheManager" class="com.wdimmmon.security.shiro.cache.JedisCacheManager"> --> <!-- <property name="cacheKeyPrefix" value="${redis.keyPrefix}_cache_" /> --> <!-- </bean> --> <bean id="shiroCacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"> <property name="cacheManager" ref="cacheManager" /> </bean> <!-- 保證實現了Shiro內部lifecycle函式的bean執行 --> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" /> <!-- AOP式方法級許可權檢查 --> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"> <property name="proxyTargetClass" value="true" /> </bean> <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" ref="securityManager" /> </bean>
注意了,這裡shiro配置的是不使用servlet容器來管理session,而是自定義了shiro自己的會話管理,這樣會導致意想不到的情況發生。再這樣的配置下,cas server登出之後,並不能使子系統的session也登出掉,子系統還是可以正常的訪問,單點登出功能並沒有實現。要想實現單點登出功能,配置spring-shiro時不能自定義session管理器,必須使用servlet容器。那要怎樣才能使用servlet容器呢?只要把我之前配置的註釋掉就可以了,shiro在沒有自定義回話管理器是會預設是用servlet的容器。
<!-- 自定義會話管理配置 --> <bean id="sessionManager" class="com.wdim.common.security.shiro.session.SessionManager"> <property name="sessionDAO" ref="sessionDAO" /> <!-- 會話超時時間,單位:毫秒 --> <property name="globalSessionTimeout" value="${session.sessionTimeout}" /> <!-- 定時清理失效會話, 清理使用者直接關閉瀏覽器造成的孤立會話 --> <property name="sessionValidationInterval" value="${session.sessionTimeoutClean}" /> <!-- <property name="sessionValidationSchedulerEnabled" value="false"/> --> <property name="sessionValidationSchedulerEnabled" value="true" /> <property name="sessionIdCookie" ref="sessionIdCookie" /> <property name="sessionIdCookieEnabled" value="true" /> </bean>
把這一個bean註釋掉,然後把引用這個bean的地方也註釋掉,就OK了。