CAS和Spring-shiro结合实现单点登出功能

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yushenzaishi/article/details/80436574

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了。
















猜你喜欢

转载自blog.csdn.net/yushenzaishi/article/details/80436574