【试水CAS-4.0.3】第08节_CAS客户端配置单点登出

本文内容包括配置单点登出、登出后自动跳转指定资源、CASServer禁用单点登出等

/**
 * @see ------------------------------------------------------------------------------------------------------------------------
 * @see CAS客户端配置单点登出
 * @see 与单点登录相对应,通过CASServer登出所有的CASClient,登录的URL是/login,登出的URL是/logout
 * @see 这里需要配置SingleSignOutFilter和SingleSignOutHttpSessionListener
 * @see SingleSignOutFilter用来使Session失效,SingleSignOutHttpSessionListener用于在Session过期时移除其对应的映射关系
 * @see 1.要为SingleSignOutFilter配置casServerUrlPrefix参数
 * @see 2.默认的登出后会跳转到CASServer的登出页,若想跳转到其它资源,可在/logout的URL后面加上service=you want to jump url
 * @see   比如http://sso.jadyer.com:8080/cas-server-web/logout?service=http://blog.csdn.net/jadyer
 * @see   但默认servcie跳转不会生效,需要CASServer配置/WEB-INF/cas.properties中的cas.logout.followServiceRedirects=true
 * @see   另外为org.jasig.cas.client.session.SingleSignOutFilter增加service参数是没用的,因为登出后跳转到指定资源属于服务端行为
 * @see 3.禁用单点登出
 * @see   CASServer/WEB-INF/cas.properties中的slo.callbacks.disabled=true
 * @see   测试时点击登出后虽然页面跳转到了默认登出页,但再次访问CASClient资源发现并没有登出,即单点登出禁用成功
 * @see 4.测试单点登出
 * @see   测试时先登出,然后在浏览器新标签页访问CASClient资源,发现会自动重定向到单点登录页
 * @see   或者登出后,点浏览器后退按钮,发现会后退到之前的CASClient资源页,但在这个页面点击任何请求,都会自动重定向到单点登录页
 * @see ------------------------------------------------------------------------------------------------------------------------
 * @create 2015-7-27 下午4:30:14
 * @author 玄玉<http://blog.csdn.net/jadyer>
 */

下面是客户端的web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
	http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:applicationContext.xml</param-value>
	</context-param>
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

	<servlet>
		<servlet-name>SpringMVC</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:applicationContext.xml</param-value>
		</init-param>
	</servlet>
	<servlet-mapping>
		<servlet-name>SpringMVC</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>

	<filter>
		<filter-name>CharacterEncodingFilter</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
		<init-param>
			<param-name>encoding</param-name>
			<param-value>UTF-8</param-value>
		</init-param>
		<init-param>
			<param-name>forceEncoding</param-name>
			<param-value>true</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>CharacterEncodingFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

	<!-- SSO -->
	<listener>
		<listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
	</listener>
	<filter>
		<filter-name>casSingleSignOutFilter</filter-name>
		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>casSingleSignOutFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	<filter>
		<filter-name>casAuthenticationFilter</filter-name>
		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>casAuthenticationFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	<filter>
		<filter-name>casTicketValidationFilter</filter-name>
		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>casTicketValidationFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	<filter>
		<filter-name>casHttpServletRequestWrapperFilter</filter-name>
		<filter-class>org.jasig.cas.client.util.HttpServletRequestWrapperFilter</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>casHttpServletRequestWrapperFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	<filter>
		<filter-name>casAssertionThreadLocalFilter</filter-name>
		<filter-class>org.jasig.cas.client.util.AssertionThreadLocalFilter</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>casAssertionThreadLocalFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
</web-app>

下面是客户端的//src//applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
						http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
						http://www.springframework.org/schema/mvc
						http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">
	<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
		<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE"/>
		<property name="ignoreResourceNotFound" value="false"/>
		<property name="locations">
			<list>
				<value>classpath:config.properties</value>
			</list>
		</property>
	</bean>
	<mvc:resources mapping="/index.jsp" location="/index.jsp"/>

	<!-- cas -->
	<bean name="casSingleSignOutFilter" class="org.jasig.cas.client.session.SingleSignOutFilter">
		<property name="casServerUrlPrefix" value="${casServerUrlPrefix}"/>
	</bean>
	<bean name="casAuthenticationFilter" class="org.jasig.cas.client.authentication.AuthenticationFilter">
		<property name="serverName" value="${casClientServerName}"/>
		<property name="casServerLoginUrl" value="${casServerLoginUrl}"/>
	</bean>
	<bean name="casTicketValidationFilter" class="org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter">
		<property name="serverName" value="${casClientServerName}"/>
		<property name="ticketValidator">
			<bean class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator">
				<constructor-arg index="0" value="${casServerUrlPrefix}"/>
			</bean>
		</property>
	</bean>
</beans>

下面是//src//config.properties

#<<Central Authentication Service>>
#where to logout
casServerLogoutUrl=http://sso.jadyer.com:8080/cas-server-web/logout
#where to login
casServerLoginUrl=http://sso.jadyer.com:8080/cas-server-web/login
#login server root
casServerUrlPrefix=http://sso.jadyer.com:8080/cas-server-web
#who am i
casClientServerName=http://boss.jadyer.com:8080

下面是//WebRoot//index.jsp

<%@ page pageEncoding="UTF-8"%>
<%@ page import="java.util.Map"%>
<%@ page import="java.net.URLDecoder"%>
<%@ page import="com.jadyer.util.ConfigUtil"%>
<%@ page import="org.jasig.cas.client.util.AssertionHolder"%>
<%@ page import="org.jasig.cas.client.authentication.AttributePrincipal"%>

<script>
function ssoLogout(){
	if(confirm('确定要退出系统吗?')){
		//top.location.href ='http://sso.jadyer.com:8080/cas-server-web/logout?service=http://blog.csdn.net/jadyer';
		//top.location.href ='http://sso.jadyer.com:8080/cas-server-web/logout?service=http://sso.jadyer.com:8080/cas-server-web/login';
		top.location.href ='<%=ConfigUtil.INSTANCE.getProperty("casServerLogoutUrl")%>';
	}
}
</script>

<body style="background-color:#CBE0C9;">
	<span style="color:red; font-size:32px; font-weight:bold;">客户端登录成功</span>
	<br>
	<br>
	<a href="javascript:ssoLogout();">我要登出</a>
</body>

<hr size="2">

<%
	AttributePrincipal principal = (AttributePrincipal)request.getUserPrincipal();
	Map<String, Object> attributes = principal.getAttributes();
	out.print("principal.getName()=" + principal.getName() + "<br/>");
	out.print("request.getRemoteUser()=" + request.getRemoteUser() + "<br/>");
	out.print("登录用户:" + attributes.get("userId") + "<br/>");
	out.print("登录时间:" + AssertionHolder.getAssertion().getAuthenticationDate() + "<br/>");
	out.print("-----------------------------------------------------------------------<br/>");
	for(Map.Entry<String,Object> entry : attributes.entrySet()){
		//服务端返回中文时需要encode,客户端接收显示中文时需要decode,否则会乱码
		out.print(entry.getKey() + "=" + URLDecoder.decode(entry.getValue().toString(), "UTF-8") + "<br/>");
	}
	out.print("-----------------------------------------------------------------------<br/>");
	Map<String, Object> attributes22 = AssertionHolder.getAssertion().getAttributes();
	for(Map.Entry<String,Object> entry : attributes22.entrySet()){
		out.print(entry.getKey() + "=" + entry.getValue() + "<br/>");
	}
	out.print("-----------------------------------------------------------------------<br/>");
	Map<String, Object> attributes33 = AssertionHolder.getAssertion().getPrincipal().getAttributes();
	for(Map.Entry<String,Object> entry : attributes33.entrySet()){
		out.print(entry.getKey() + "=" + entry.getValue() + "<br/>");
	}
%>

最后是读取配置文件的工具类ConfigUtil.java

package com.jadyer.util;

import java.io.IOException;
import java.util.Properties;
import java.util.regex.Pattern;

/**
 * 配置文件读取工具类
 * @see -----------------------------------------------------------------------------------------------------------
 * @see 用法为ConfigUtil.INSTANCE.getProperty("KJJF.databaseURL")
 * @see 采用枚举的方式,也是Effective Java作者Josh Bloch提倡的方式,它不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象
 * @see -----------------------------------------------------------------------------------------------------------
 * @version v2.1
 * @history v2.1-->增加<code>getPropertyBySysKey()</code>方法,用于获取配置文件的键值中含系统属性时的值,详见该方法注释
 * @history v2.0-->采用枚举的方式实现单例
 * @history v1.0-->通过内部类实现单例
 * @update 2015-2-2 下午05:22:03
 * @create Jun 7, 2012 5:30:10 PM
 * @author 玄玉<http://blog.csdn.net/jadyer>
 */
public enum ConfigUtil {
	INSTANCE;

	private Properties config;

	private ConfigUtil(){
		config = new Properties();
		try {
			config.load(ConfigUtil.class.getResourceAsStream("/config.properties"));
			System.out.println("Load /config.properties SUCCESS...");
		} catch (IOException e) {
			System.out.println("Load /config.properties Error...");
			e.printStackTrace();
			throw new ExceptionInInitializerError("加载系统配置文件失败...");
		}
	}

	public String getProperty(String key){
		return config.getProperty(key);
	}

	public int getPropertyForInt(String key){
		return Integer.parseInt(config.getProperty(key));
	}

	/**
	 * 配置文件的键值中含系统属性时的获取方式
	 * @see 若配置文件的某个键值含类似于${user.dir}的写法,如log=${user.dir}/app.log
	 * @see 则可以通过该方法使用系统属性中user.dir的值,替换掉配置文件键值中的${user.dir}
	 * @create 2015-2-2 下午05:22:03
	 * @author 玄玉<http://blog.csdn.net/jadyer>
	 */
	public String getPropertyBySysKey(String key){
		String value = config.getProperty(key);
		if(null!=value && Pattern.compile("\\$\\{\\w+(\\.\\w+)*\\}").matcher(value).find()){
			String sysKey = value.substring(value.indexOf("${")+2, value.indexOf("}"));
			value = value.replace("${"+sysKey+"}", System.getProperty(sysKey));
		}
		return value;
	}
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-05 02:23:09

【试水CAS-4.0.3】第08节_CAS客户端配置单点登出的相关文章

【试水CAS-4.0.3】第07节_CAS客户端配置单点登录

本文源码下载:http://download.csdn.net/detail/jadyer/8934207 /** * @see CAS客户端配置 * @see ------------------------------------------------------------------------------------------------------------------------ * @see 这里用的是cas-client-core-3.4.0.jar(这是2015-07-

源代码解读Cas实现单点登出(single sign out)功能实现原理

关于Cas实现单点登入(single sing on)功能的文章在网上介绍的比较多,想必大家多多少少都已经有所了解,在此就不再做具体介绍.如果不清楚的,那只能等我把single sign on这块整理出来后再了解了.当然去cas官方网站也是有很多的文章进行介绍.cas官网http://www.ja-sig.org/products/cas/. ok,现在开始本文的重点内容讲解,先来了解一下cas 实现single sign 的原理,如图所示: 登出原理图 从第一张图中,当一个web浏览器登录到应

源代码解读Cas实现单点登出(single sign out)功能实现原理--转

关于Cas实现单点登入(single sing on)功能的文章在网上介绍的比较多,想必大家多多少少都已经有所了解,在此就不再做具体介绍.如果不清楚的,那只能等我把single sign on这块整理出来后再了解了.当然去cas官方网站也是有很多的文章进行介绍.cas官网http://www.ja-sig.org/products/cas/. ok,现在开始本文的重点内容讲解,先来了解一下cas 实现single sign out的原理,如图所示: 图一                     

CAS 单点登出失效的问题(源码跟踪)

一.环境说明 服务端:cas-server-3.5.2 客户端:cas-client-3.2.1+spring mvc 说明:服务端与客户端均是走的Https 客户端配置文件: applicationContext-cas.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xm

单点登录CAS使用记(六):单点登出、单点注销

单点登出基本上没有啥配置 直接在原来logout的时候,重定向到Cas-Server的logout方法 @RequestSecurity @RequestMapping(value = "loginout", method = { RequestMethod.GET, RequestMethod.POST }) public String loginout(HttpSession session) { session.invalidate(); return "redirec

cas单点登出

由于项目需求要实现单点登出需要在网上找了N久终于实现单点登出. 使用cas-server-core-3.3.3.jar(CAS Server 3.3.3) 使用cas-client-core-3.1.3.jar(CAS Client 3.1.3) 项目结合CAS SpringSecurity SSH 普通项目(没有结合Spring Security)的可以在web.xml中加入如下代码 [xhtml] view plaincopy <filter> <filter-name>CAS

CAS客户端配置

1. 导出证书 以上操作会在当前目录产生文件:ssodemo.crt(需要用到的文件请看CAS服务端配置那篇文章) 2. 客户端导入证书 以上操作会在jdk安装目录jre\lib\security下产生文件:cacerts 注意:多台电脑要重复以上操作,每个jdk都要导入这个文件 另一种导入证书的方法详见:http://www.cnblogs.com/cxyj/p/3884507.html 3. 添加cas客户端jar包到自己需要单点登录的web应用web-inf/lib目录下 下载地址:htt

cas系列-cas登出(四)

跟登陆一样,登出操作也很重要.由于是多应用间操作,状态保持也是一个要点,根据登出的影响范围,可以将登出操作分为两类: 单应用登出 单点登出(多应用登出) 顾名思义,单应用登出即登出只影响被操作的应用会话,其他应用和CAS会话状态不受影响.这也就需要你退出每一个应用,如果应用数量较多,每次退出可能都是件力气活.单点登出是结束SSO会话,所有建立在SSO会话上的的应用会话都会进行登出.使用户的状态保持一致.当应用间会话记录不一致时,登出操作可能会造成会话记录丢失; 登出操作: /logout?ser

【试水CAS-4.0.3】第09节_CAS服务端RememberMe

本文源码下载:http://download.csdn.net/detail/jadyer/8940967 /** * @see ------------------------------------------------------------------------------------------------------------------------ * @see 先介绍一下CAS-4.0.3服务端的来自cas.properties中的一些其它配置项 * @see 1.cas.