完整版见https://jadyer.cn/2015/07/27/sso-cas-client-logout/
本文内容包括配置单点登出、登出后自动跳转指定资源、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 玄玉
*/
下面是客户端的web.xml
contextConfigLocation
classpath:applicationContext.xml
org.springframework.web.context.ContextLoaderListener
SpringMVC
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:applicationContext.xml
SpringMVC
/
CharacterEncodingFilter
org.springframework.web.filter.CharacterEncodingFilter
encoding
UTF-8
forceEncoding
true
CharacterEncodingFilter
/*
org.jasig.cas.client.session.SingleSignOutHttpSessionListener
casSingleSignOutFilter
org.springframework.web.filter.DelegatingFilterProxy
casSingleSignOutFilter
/*
casAuthenticationFilter
org.springframework.web.filter.DelegatingFilterProxy
casAuthenticationFilter
/*
casTicketValidationFilter
org.springframework.web.filter.DelegatingFilterProxy
casTicketValidationFilter
/*
casHttpServletRequestWrapperFilter
org.jasig.cas.client.util.HttpServletRequestWrapperFilter
casHttpServletRequestWrapperFilter
/*
casAssertionThreadLocalFilter
org.jasig.cas.client.util.AssertionThreadLocalFilter
casAssertionThreadLocalFilter
/*
下面是客户端的//src//applicationContext.xml
classpath:config.properties
下面是//src//config.properties
#<>
#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"%>
客户端登录成功
我要登出
<%
AttributePrincipal principal = (AttributePrincipal)request.getUserPrincipal();
Map attributes = principal.getAttributes();
out.print("principal.getName()=" + principal.getName() + "
");
out.print("request.getRemoteUser()=" + request.getRemoteUser() + "
");
out.print("登录用户:" + attributes.get("userId") + "
");
out.print("登录时间:" + AssertionHolder.getAssertion().getAuthenticationDate() + "
");
out.print("-----------------------------------------------------------------------
");
for(Map.Entry entry : attributes.entrySet()){
//服务端返回中文时需要encode,客户端接收显示中文时需要decode,否则会乱码
out.print(entry.getKey() + "=" + URLDecoder.decode(entry.getValue().toString(), "UTF-8") + "
");
}
out.print("-----------------------------------------------------------------------
");
Map attributes22 = AssertionHolder.getAssertion().getAttributes();
for(Map.Entry entry : attributes22.entrySet()){
out.print(entry.getKey() + "=" + entry.getValue() + "
");
}
out.print("-----------------------------------------------------------------------
");
Map attributes33 = AssertionHolder.getAssertion().getPrincipal().getAttributes();
for(Map.Entry entry : attributes33.entrySet()){
out.print(entry.getKey() + "=" + entry.getValue() + "
");
}
%>
最后是读取配置文件的工具类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-->增加getPropertyBySysKey()
方法,用于获取配置文件的键值中含系统属性时的值,详见该方法注释
* @history v2.0-->采用枚举的方式实现单例
* @history v1.0-->通过内部类实现单例
* @update 2015-2-2 下午05:22:03
* @create Jun 7, 2012 5:30:10 PM
* @author 玄玉
*/
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 玄玉
*/
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;
}
}