- 浏览: 494790 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (301)
- Swing技术 (1)
- Linux (1)
- Javascript (22)
- 数据结构和算法 (3)
- J2SE (36)
- workflow (5)
- 设计模式 (14)
- web service (19)
- Ajax (14)
- 中间件 & 服务器 (8)
- 多线程 (9)
- Oracle (52)
- sys & soft (10)
- JMS (3)
- sso (9)
- android (11)
- struts2 (10)
- web协议 (2)
- 分布式 (2)
- PM (2)
- OLAP (3)
- Redis (2)
- Hibernate (7)
- ibatis (2)
- SQLServer (1)
- maven (3)
- Spring (7)
- Jsp (2)
- slf4j (1)
- jQuery (15)
- 权限 (1)
- 系统集成 (1)
- 笔记 (1)
- Freemarker (2)
- 项目管理 (1)
- eclipse (3)
- GIS (1)
- NoSql (3)
- win10 (1)
- win10网络 (2)
- 底层 (3)
- 数据库 (0)
最新评论
-
kabuto_v:
请问那种图,uml图是怎么画出来的呢?是您自己手工画的,还是有 ...
FastJSON 序列化、反序列化实现 -
梦行Monxin商城系统:
电商实例、业务并发、网站并发及解决方法 -
rockethj8:
client 㓟有一个参数是可以忽略一些URL 不进行验证登录 ...
SSO 之 (单点登录)实施中遇到的几个问题 -
mengxiangfeiyan:
好啊。。。。。
Oracle删除表,删除数据以及恢复数据、利用现有表创建新表
http://blog.csdn.net/yan_dk/article/details/7092094
目录(?)[+]
单点登录应用中,遇到如下的几个问题:1.超时问题;2.jsessionid问题;3.单点退出时有时子系统未能正常退出;4.有些请求路径不需要单点登录过滤器拦截;5.不同应用服务实现可能要求SSO客户端做适应性改造。我们具体分析一下,并提出解决方法。
1.超时问题
我们提供的CAS开源单点登录SSO组件,它部署节点主要有2个:SSO服务器(部署内容为一个web应用)、应用系统客户端(部署内容为cas客户端casclient.jar包和相关配置文件)。因此我们根据SSO机制分析一下什么情况下会出现超时。多个应用系统进行SSO集成后,SSO单点登录过程中,登录成功后,应用系统客户端(以下用浏览器客户端为例)的session会保存认证后的用户上下文,SSO服务器会生成一个用户凭证票据(TGT)并缓存起来,浏览器客户端会保存TGC(浏览器cookie中存储的TGT),TGT是作为发放SSO访问服务的票据(ST)的一个凭证票据,发放ST票据后才能正常访问。而浏览器客户端的session会超时(如一般web应用客户端可以设置session的timeout值为30分钟或更长),超时后会让session失效,清空用户上下文,TGC因为仍然是保存在浏览器cookie中,只有关闭浏览器才会清除。SSO服务器端的超时主要是TGT、ST超时,我们一般会设置超时值TGT为2小时,ST为5分钟。关于ST票据使用,一般在首次SSO访问服务时携带着该票据参数,验证票据后能正常访问后,SSO服务器就将此ST销毁失效了;关于TGT票据的使用,一般是正常访问时一直保持为超时时间(2小时),除非做单点退出会销毁TGT。
基于以上分析,我们可以得出结论,SSO的超时主要涉及2个要素:浏览器的session超时值、TGT的超时值。一般系统设置TGT的超时值>浏览器的session超时值,那么可能有2种超时情况:1.TGT超时(浏览器session超时值小,自然也超时);2.浏览器session超时,TGT不超时。
第一种“1.TGT超时”,这个处理很简单,用户的有效凭证票据都失效了,自然要重新取得有效凭证票据TGT,需要做的就是重新跳转到登录页面重新登录。
第二种”2.浏览器session超时,TGT不超时“,这时SSO服务器的TGT票据,以及浏览器客户端的TGC(cookie中的TGT)仍然有效。浏览器客户端再次SSO访问时就可以携带TGC(与服务器的TGT对应),向SSO服务器重新发送取得票据ST请求,取得票据ST后,携带着有效ST票据可以正常访问应用系统了。这个过程是浏览器客户端与SSO服务器的一个通讯交互,用户可能感觉不到,不会出现中断,好像能连续访问,这是为了给用户一个友好的访问体验。明白这个机制,就知道实际上是SSO机制在后台起作用了。
2.jsessionid问题
jsessionid是java客户端与应用服务器维持session的一个标识,其他语言客户端(如php)有其他标识关键字,具体是什么还不太了解。jsessionid一般存在于浏览器cookie中的(这个一般java客户端连接到应用服务器会自动执行的),一般情况下不会出现在url中,服务器会从客户端的cookie中取出来,但是如果浏览器禁用了cookie的话,就要重写url了,显式的将jsessionid重写到Url中,方便服务器来通过这个找到session的id。CAS开源单点登录SSO组件就提供了这个机制。我研究了CAS源码,基本明白了jsessionid的处理机制。大致原理如下:用户访问业务系统,SSO客户端拦截,重定向到SSO服务器认证时,就将请求路径uri中写入";jsessionid=具体的session值",SSO服务器可以分辨出这个标识值与其他客户端请求不同,进行认证处理,返回的响应给客户端cookie同时也设置了jsessionid的值,之所以在uri和cookie中都设置了jsessionid,是为了双重保障能设置jsessionid值。最后单点登录成功后,返回业务系统访问地址也带有jsessionid参数,这个在uri地址中看起来很别扭。
提供2种解决方法,如下:
1) 可以在登录页面地址的请求地址参数中加入参数”&method=POST“(记住这里要求POST大写),这样就可以在最后返回的访问uri中不显示jsessionid。
2)修改代码如下:
类org.jasig.cas.util.UrlUtils中增加方法cleanupUrl
public static final String cleanupUrl(final String url) {
if (url == null) {
return null;
}
final int jsessionPosition = url.indexOf(";jsession");
if (jsessionPosition == -1) {
return url;
}
final int questionMarkPosition = url.indexOf("?");
if (questionMarkPosition < jsessionPosition) {
return url.substring(0, url.indexOf(";jsession"));
}
return url.substring(0, jsessionPosition)
+ url.substring(questionMarkPosition);
}
类org.jasig.cas.web.flow.DynamicRedirectViewSelector的makeEntrySelection方法中修改如下行
default:
// return new ExternalRedirect(serviceResponse.getUrl());//注释源码
return new ExternalRedirect(UrlUtils.cleanupUrl(serviceResponse.getUrl()));//清除url中jsessionid
这样运行后,url路径中的jsessionid就不存在了。
3.单点退出时有时子系统未能正常退出
我们知道正常情况下,以用户A单点登录系统,正常访问各子系统,然后执行单点退出时,退出成功后一般跳转回到登录页面要求重新登录,这时各已登录的子系统session被销毁,再次以另一个用户B登录进入后,各子系统显示的应当是用户B的数据信息。可是有时却发现有些子系统仍然显示的是用户A的数据信息,这属于偶发现象。现在分析一下产生这种情况可能的原因,找出解决办法。
若想了解单点退出机制原理,我们可以先看看CAS源码的SSO单点退出实现机制。参见我的博客中 http://blog.csdn.net/yan_dk/article/details/7095091单点登录实现机制的【单点退出】部分。
我们看一下源码,看到退出时调用类AbstractWebApplicationService的方法logOutOfService(),代码如下
public synchronized boolean logOutOfService(final String sessionIdentifier) {
if (this.loggedOutAlready) {
return true;
}
LOG.debug("Sending logout request for: " + getId());
final String logoutRequest = "<samlp:LogoutRequest xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\" ID=\""
+ GENERATOR.getNewTicketId("LR")
+ "\" Version=\"2.0\" IssueInstant=\"" + SamlUtils.getCurrentDateAndTime()
+ "\"><saml:NameID xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\">@NOT_USED@</saml:NameID><samlp:SessionIndex>"
+ sessionIdentifier + "</samlp:SessionIndex></samlp:LogoutRequest>";
HttpURLConnection connection = null;
try {
final URL logoutUrl = new URL(getOriginalUrl());
final String output = "logoutRequest=" + URLEncoder.encode(logoutRequest, "UTF-8");
connection = (HttpURLConnection) logoutUrl.openConnection();
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setRequestProperty("Content-Length", ""
+ Integer.toString(output.getBytes().length));
connection.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
final DataOutputStream printout = new DataOutputStream(connection
.getOutputStream());
printout.writeBytes(output);
printout.flush();
printout.close();
final BufferedReader in = new BufferedReader(new InputStreamReader(connection
.getInputStream()));
while (in.readLine() != null) {
// nothing to do
}
return true;
} catch (final Exception e) {
return false;
} finally {
if (connection != null) {
connection.disconnect();
}
this.loggedOutAlready = true;
}
}
我们看到红字部分,在调用发生异常时,代码是直接返回false的,也就是说单点退出发生错误时,SSO服务器并没有做异常处理,直接返回,这样就有可能在出现异常时(比如网络瞬时闪断),虽然系统界面退出后返回登录页面,但是SSO服务器并没有退出处理,没有销毁登录会话,所以就可能出现没有真正退出,仍然显示前一用户的会话信息。这个应该是CAS源码的一个bug,解决方法是在此处积累错误日志,并抛出异常处理。这样应该能解决此问题。修改代码如下:
。。。
} catch (final Exception e) {
LOG.error("--------------Sending logout request for URL: " + getOriginalUrl()+"Network connection failed.");
throw new Exception(e);
} finally {
。。。
说明:
4.有些请求路径不需要单点登录过滤器拦截
业务系统web应用在使用单点登录组件时,有些请求路径不需要单点登录过滤器拦截,比如公共开放的路径,不需要认证都可以自由访问的路径,单点登录过滤器配置的映射路径一般以通配符匹配路径,但要把这些路径单独提取出来,让过滤器不拦截做单点登录处理,就需要对原有过滤器进行扩展改造,才能实现这个功能。
扩展实现代码如下:
public class CASFilter implements Filter {
public static enum ResponseType {
BREAK, GOON, RETURN
}
...
public void doFilter(
ServletRequest request,
ServletResponse response,
FilterChain fc){
。。。
CASReceipt receipt = (CASReceipt) session.getAttribute(CAS_FILTER_RECEIPT);
if (receipt != null && isReceiptAcceptable(receipt)) {
log.trace("CAS_FILTER_RECEIPT attribute was present and acceptable - passing request through filter..");
fc.doFilter(request, response);
return;
}else{
responeType = beforeDoSSOFilter(request, response);
if(ResponseType.RETURN==responeType){
return ;
}else if(ResponseType.BREAK==responeType) {
fc.doFilter(request, response);
return;
} //else go on
}
}
//过滤器的前置处理
public ResponseType beforeDoSSOFilter(ServletRequest request,
ServletResponse response) {
return ResponseType.GOON;
}
}
注:主要看原CASFilter 类红字部分扩展代码。
扩展实现类BMCASFilter
package com.sitechasia.sso.bmext;
public class BMCASFilter extends CASFilter {
private final Log log = LogFactory.getLog(this.getClass());
private static String ssoclient_passedPathSet;//设置不被sso过滤器拦截的请求路径,需要符合url路径通配符,多个路径可以","分割
public static final String PASSEDPATHSET_INIT_PARAM="passedPathSet";//web.xml配置文件中的参数
@Override
public void init(FilterConfig config) throws ServletException {
super.init(config);
ssoclient_passedPathSet = SSOClientPropertiesSingleton.getInstance().getProperty(ClientConstants.SSOCLIENT_PASSEDPATHSET)==null?config.getInitParameter(PASSEDPATHSET_INIT_PARAM):SSOClientPropertiesSingleton.getInstance().getProperty(ClientConstants.SSOCLIENT_PASSEDPATHSET);
}
@Override
public ResponseType beforeDoSSOFilter(ServletRequest request,
ServletResponse response) {
if (ssoclient_passedPathSet != null) {//路径过滤
HttpServletRequest httpRequest =(HttpServletRequest)request;
String requestPath = httpRequest.getRequestURI();
// String ls_requestPath = UrlUtils.buildFullRequestUrl(httpRequest.getScheme(), httpRequest.getServerName(), httpRequest.getServerPort(), requestPath, null);
PathMatcher matcher = new AntPathMatcher();
String passedPaths[]=null;
passedPaths =ssoclient_passedPathSet.split(",");
if(passedPaths!=null){
boolean flag;
for (String passedPath : passedPaths) {
flag = matcher.match(passedPath, requestPath);//ls_requestPath
if(flag){
log.info("sso client request path '"+requestPath+"'is matched,filter chain will be continued.");
return ResponseType.BREAK;
}
}
}
}
return ResponseType.GOON;
}
}
web.xml文件中配置修改如下:
<filter>
<description>单点登陆请求过滤器</description>
<filter-name>CASFilter</filter-name>
<filter-class>com.sitechasia.sso.dmext.filter.DMCASFilter</filter-class>
...
<init-param>
<description>排除路径</description>
<param-name>passedPathSet</param-name>
<param-value>
/**/restful/userLogin/findPassword,
/**/restful/userLogin/findIllegalLoginCount,
/**/restful/tenantManager/**,
/**/restful/lock/**,
/**/restful/export/**
</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CASFilter</filter-name>
<url-pattern>/index.jsp</url-pattern>
</filter-mapping>
。。。
注:红字部分为相应配置内容扩展部分
经过上述这样扩展,配置的排除路径作为请求时,单点登录过滤拦截就会忽略处理,实现了目标功能要求。
5.不同应用服务实现要求SSO客户端做适应性改造
不同应用服务,对请求的处理方式不同,SSO客户端常规方法不能处理的需要进行适应性改造。我们先看一下SSO客户端常规方法处理请求,web应用中定义一个过滤器casfilter,并配置对安全资源拦截,首次登录系统、或者访问超时时,安全资源的请求被过滤器casfilter拦截,将安全资源路径包装为service参数,并重定向(http状态为302)到SSO服务器地址进行认证,输入凭证信息(用户名、密码等),SSO服务器经过认证、验证票据机制处理,认证成功后,登录通过后继续访问安全资源,再次访问安全资源时,过滤器casfilter拦截,根据用户上下文判断用户已经登录,就不再拦截安全资源,直接正常访问安全资源。而有些应用中使用其他方式处理请求,按上述常规方法不好处理,下面举实例来看看解决方案。
5.1.Ajax客户端
公司有一个应用系统使用Ajax客户端来处理请求并取得响应,在访问超时时,Ajax客户端请求由于使用异步处理技术(只局部刷新页面),不能将请求继续302重定向到SSO服务器重新认证处理,不能继续访问安全资源,界面响应处于一直延迟状态,很不友好。我们针对此应用进行适应性改造。改造要点如下:
我们约定应用系统的一个Ajax请求的标记(如ajaxRequestFlag=ajaxRequest),在安全资源ajax调用请求时携带此请求参数,还约定一个超时请求的响应状态值(如555),SSO客户端的过滤器casfilter的相应类程序对此约定进行了相应的改造。
应用系统的安全资源页面中引入文件(HttpStatusSSO.js)SSO对Axax请求的http状态的处理,其中有超时时的状态处理、判断是否登录、验证票据等的处理,都是通过ajax请求方式来处理的,其中依赖一个验证票据的资源ticketValidate.jsp。
经过上述改造后,应用系统的安全资源发送携带ajax请求标记的请求,在超时请求时,SSO客户端返回约定响应码(555),HttpStatusSSO.js文件判断处理后转发给相应的登录页面重新认证。单点登录的访问也能够正常的实现功能。这样只扩展了SSO客户端组件的实现,向下版本兼容,保证了SSO组件的统一完整性。
上述改造方式是通过实践开发出来的,可能还有更好的方法来改造扩展,今后持续改进吧。
后记:现在官方的CAS源码3.4版本已经支持Ajax请求的客户端,它的实现机制有待于进一步的研究,大家可以参考。
5.2.多域认证
有时我们遇到,不同子系统的认证实现的数据源可能来自一个用户数据库。我公司就是这种情况,采用Saas模式运营的软件,认证的用户来源于不同的租户或者域,基于这样的情况,我们对SSO进行了扩展,主要提供了认证接口,认证实现上,可以在认证时动态取得租户对应的数据源,对用户进行认证处理。举例如下:
5.3.SSO集中认证登录页面需要在业务子系统中定制
SSO集中认证的登录页面默认是放在SSO服务器端的,样式也很不好看,用户需要把登录页面放在业务子系统中自行定制,我们对SSO进行了扩展,思路也很简单,主要是将显示默认登录页面的调用,变成了远程调用业务子系统的页面地址,这个地址可以作为配置参数来配置。举例如下
目录(?)[+]
单点登录应用中,遇到如下的几个问题:1.超时问题;2.jsessionid问题;3.单点退出时有时子系统未能正常退出;4.有些请求路径不需要单点登录过滤器拦截;5.不同应用服务实现可能要求SSO客户端做适应性改造。我们具体分析一下,并提出解决方法。
1.超时问题
我们提供的CAS开源单点登录SSO组件,它部署节点主要有2个:SSO服务器(部署内容为一个web应用)、应用系统客户端(部署内容为cas客户端casclient.jar包和相关配置文件)。因此我们根据SSO机制分析一下什么情况下会出现超时。多个应用系统进行SSO集成后,SSO单点登录过程中,登录成功后,应用系统客户端(以下用浏览器客户端为例)的session会保存认证后的用户上下文,SSO服务器会生成一个用户凭证票据(TGT)并缓存起来,浏览器客户端会保存TGC(浏览器cookie中存储的TGT),TGT是作为发放SSO访问服务的票据(ST)的一个凭证票据,发放ST票据后才能正常访问。而浏览器客户端的session会超时(如一般web应用客户端可以设置session的timeout值为30分钟或更长),超时后会让session失效,清空用户上下文,TGC因为仍然是保存在浏览器cookie中,只有关闭浏览器才会清除。SSO服务器端的超时主要是TGT、ST超时,我们一般会设置超时值TGT为2小时,ST为5分钟。关于ST票据使用,一般在首次SSO访问服务时携带着该票据参数,验证票据后能正常访问后,SSO服务器就将此ST销毁失效了;关于TGT票据的使用,一般是正常访问时一直保持为超时时间(2小时),除非做单点退出会销毁TGT。
基于以上分析,我们可以得出结论,SSO的超时主要涉及2个要素:浏览器的session超时值、TGT的超时值。一般系统设置TGT的超时值>浏览器的session超时值,那么可能有2种超时情况:1.TGT超时(浏览器session超时值小,自然也超时);2.浏览器session超时,TGT不超时。
第一种“1.TGT超时”,这个处理很简单,用户的有效凭证票据都失效了,自然要重新取得有效凭证票据TGT,需要做的就是重新跳转到登录页面重新登录。
第二种”2.浏览器session超时,TGT不超时“,这时SSO服务器的TGT票据,以及浏览器客户端的TGC(cookie中的TGT)仍然有效。浏览器客户端再次SSO访问时就可以携带TGC(与服务器的TGT对应),向SSO服务器重新发送取得票据ST请求,取得票据ST后,携带着有效ST票据可以正常访问应用系统了。这个过程是浏览器客户端与SSO服务器的一个通讯交互,用户可能感觉不到,不会出现中断,好像能连续访问,这是为了给用户一个友好的访问体验。明白这个机制,就知道实际上是SSO机制在后台起作用了。
2.jsessionid问题
jsessionid是java客户端与应用服务器维持session的一个标识,其他语言客户端(如php)有其他标识关键字,具体是什么还不太了解。jsessionid一般存在于浏览器cookie中的(这个一般java客户端连接到应用服务器会自动执行的),一般情况下不会出现在url中,服务器会从客户端的cookie中取出来,但是如果浏览器禁用了cookie的话,就要重写url了,显式的将jsessionid重写到Url中,方便服务器来通过这个找到session的id。CAS开源单点登录SSO组件就提供了这个机制。我研究了CAS源码,基本明白了jsessionid的处理机制。大致原理如下:用户访问业务系统,SSO客户端拦截,重定向到SSO服务器认证时,就将请求路径uri中写入";jsessionid=具体的session值",SSO服务器可以分辨出这个标识值与其他客户端请求不同,进行认证处理,返回的响应给客户端cookie同时也设置了jsessionid的值,之所以在uri和cookie中都设置了jsessionid,是为了双重保障能设置jsessionid值。最后单点登录成功后,返回业务系统访问地址也带有jsessionid参数,这个在uri地址中看起来很别扭。
提供2种解决方法,如下:
1) 可以在登录页面地址的请求地址参数中加入参数”&method=POST“(记住这里要求POST大写),这样就可以在最后返回的访问uri中不显示jsessionid。
2)修改代码如下:
类org.jasig.cas.util.UrlUtils中增加方法cleanupUrl
public static final String cleanupUrl(final String url) {
if (url == null) {
return null;
}
final int jsessionPosition = url.indexOf(";jsession");
if (jsessionPosition == -1) {
return url;
}
final int questionMarkPosition = url.indexOf("?");
if (questionMarkPosition < jsessionPosition) {
return url.substring(0, url.indexOf(";jsession"));
}
return url.substring(0, jsessionPosition)
+ url.substring(questionMarkPosition);
}
类org.jasig.cas.web.flow.DynamicRedirectViewSelector的makeEntrySelection方法中修改如下行
default:
// return new ExternalRedirect(serviceResponse.getUrl());//注释源码
return new ExternalRedirect(UrlUtils.cleanupUrl(serviceResponse.getUrl()));//清除url中jsessionid
这样运行后,url路径中的jsessionid就不存在了。
3.单点退出时有时子系统未能正常退出
我们知道正常情况下,以用户A单点登录系统,正常访问各子系统,然后执行单点退出时,退出成功后一般跳转回到登录页面要求重新登录,这时各已登录的子系统session被销毁,再次以另一个用户B登录进入后,各子系统显示的应当是用户B的数据信息。可是有时却发现有些子系统仍然显示的是用户A的数据信息,这属于偶发现象。现在分析一下产生这种情况可能的原因,找出解决办法。
若想了解单点退出机制原理,我们可以先看看CAS源码的SSO单点退出实现机制。参见我的博客中 http://blog.csdn.net/yan_dk/article/details/7095091单点登录实现机制的【单点退出】部分。
我们看一下源码,看到退出时调用类AbstractWebApplicationService的方法logOutOfService(),代码如下
public synchronized boolean logOutOfService(final String sessionIdentifier) {
if (this.loggedOutAlready) {
return true;
}
LOG.debug("Sending logout request for: " + getId());
final String logoutRequest = "<samlp:LogoutRequest xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\" ID=\""
+ GENERATOR.getNewTicketId("LR")
+ "\" Version=\"2.0\" IssueInstant=\"" + SamlUtils.getCurrentDateAndTime()
+ "\"><saml:NameID xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\">@NOT_USED@</saml:NameID><samlp:SessionIndex>"
+ sessionIdentifier + "</samlp:SessionIndex></samlp:LogoutRequest>";
HttpURLConnection connection = null;
try {
final URL logoutUrl = new URL(getOriginalUrl());
final String output = "logoutRequest=" + URLEncoder.encode(logoutRequest, "UTF-8");
connection = (HttpURLConnection) logoutUrl.openConnection();
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setRequestProperty("Content-Length", ""
+ Integer.toString(output.getBytes().length));
connection.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
final DataOutputStream printout = new DataOutputStream(connection
.getOutputStream());
printout.writeBytes(output);
printout.flush();
printout.close();
final BufferedReader in = new BufferedReader(new InputStreamReader(connection
.getInputStream()));
while (in.readLine() != null) {
// nothing to do
}
return true;
} catch (final Exception e) {
return false;
} finally {
if (connection != null) {
connection.disconnect();
}
this.loggedOutAlready = true;
}
}
我们看到红字部分,在调用发生异常时,代码是直接返回false的,也就是说单点退出发生错误时,SSO服务器并没有做异常处理,直接返回,这样就有可能在出现异常时(比如网络瞬时闪断),虽然系统界面退出后返回登录页面,但是SSO服务器并没有退出处理,没有销毁登录会话,所以就可能出现没有真正退出,仍然显示前一用户的会话信息。这个应该是CAS源码的一个bug,解决方法是在此处积累错误日志,并抛出异常处理。这样应该能解决此问题。修改代码如下:
。。。
} catch (final Exception e) {
LOG.error("--------------Sending logout request for URL: " + getOriginalUrl()+"Network connection failed.");
throw new Exception(e);
} finally {
。。。
说明:
4.有些请求路径不需要单点登录过滤器拦截
业务系统web应用在使用单点登录组件时,有些请求路径不需要单点登录过滤器拦截,比如公共开放的路径,不需要认证都可以自由访问的路径,单点登录过滤器配置的映射路径一般以通配符匹配路径,但要把这些路径单独提取出来,让过滤器不拦截做单点登录处理,就需要对原有过滤器进行扩展改造,才能实现这个功能。
扩展实现代码如下:
public class CASFilter implements Filter {
public static enum ResponseType {
BREAK, GOON, RETURN
}
...
public void doFilter(
ServletRequest request,
ServletResponse response,
FilterChain fc){
。。。
CASReceipt receipt = (CASReceipt) session.getAttribute(CAS_FILTER_RECEIPT);
if (receipt != null && isReceiptAcceptable(receipt)) {
log.trace("CAS_FILTER_RECEIPT attribute was present and acceptable - passing request through filter..");
fc.doFilter(request, response);
return;
}else{
responeType = beforeDoSSOFilter(request, response);
if(ResponseType.RETURN==responeType){
return ;
}else if(ResponseType.BREAK==responeType) {
fc.doFilter(request, response);
return;
} //else go on
}
}
//过滤器的前置处理
public ResponseType beforeDoSSOFilter(ServletRequest request,
ServletResponse response) {
return ResponseType.GOON;
}
}
注:主要看原CASFilter 类红字部分扩展代码。
扩展实现类BMCASFilter
package com.sitechasia.sso.bmext;
public class BMCASFilter extends CASFilter {
private final Log log = LogFactory.getLog(this.getClass());
private static String ssoclient_passedPathSet;//设置不被sso过滤器拦截的请求路径,需要符合url路径通配符,多个路径可以","分割
public static final String PASSEDPATHSET_INIT_PARAM="passedPathSet";//web.xml配置文件中的参数
@Override
public void init(FilterConfig config) throws ServletException {
super.init(config);
ssoclient_passedPathSet = SSOClientPropertiesSingleton.getInstance().getProperty(ClientConstants.SSOCLIENT_PASSEDPATHSET)==null?config.getInitParameter(PASSEDPATHSET_INIT_PARAM):SSOClientPropertiesSingleton.getInstance().getProperty(ClientConstants.SSOCLIENT_PASSEDPATHSET);
}
@Override
public ResponseType beforeDoSSOFilter(ServletRequest request,
ServletResponse response) {
if (ssoclient_passedPathSet != null) {//路径过滤
HttpServletRequest httpRequest =(HttpServletRequest)request;
String requestPath = httpRequest.getRequestURI();
// String ls_requestPath = UrlUtils.buildFullRequestUrl(httpRequest.getScheme(), httpRequest.getServerName(), httpRequest.getServerPort(), requestPath, null);
PathMatcher matcher = new AntPathMatcher();
String passedPaths[]=null;
passedPaths =ssoclient_passedPathSet.split(",");
if(passedPaths!=null){
boolean flag;
for (String passedPath : passedPaths) {
flag = matcher.match(passedPath, requestPath);//ls_requestPath
if(flag){
log.info("sso client request path '"+requestPath+"'is matched,filter chain will be continued.");
return ResponseType.BREAK;
}
}
}
}
return ResponseType.GOON;
}
}
web.xml文件中配置修改如下:
<filter>
<description>单点登陆请求过滤器</description>
<filter-name>CASFilter</filter-name>
<filter-class>com.sitechasia.sso.dmext.filter.DMCASFilter</filter-class>
...
<init-param>
<description>排除路径</description>
<param-name>passedPathSet</param-name>
<param-value>
/**/restful/userLogin/findPassword,
/**/restful/userLogin/findIllegalLoginCount,
/**/restful/tenantManager/**,
/**/restful/lock/**,
/**/restful/export/**
</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CASFilter</filter-name>
<url-pattern>/index.jsp</url-pattern>
</filter-mapping>
。。。
注:红字部分为相应配置内容扩展部分
经过上述这样扩展,配置的排除路径作为请求时,单点登录过滤拦截就会忽略处理,实现了目标功能要求。
5.不同应用服务实现要求SSO客户端做适应性改造
不同应用服务,对请求的处理方式不同,SSO客户端常规方法不能处理的需要进行适应性改造。我们先看一下SSO客户端常规方法处理请求,web应用中定义一个过滤器casfilter,并配置对安全资源拦截,首次登录系统、或者访问超时时,安全资源的请求被过滤器casfilter拦截,将安全资源路径包装为service参数,并重定向(http状态为302)到SSO服务器地址进行认证,输入凭证信息(用户名、密码等),SSO服务器经过认证、验证票据机制处理,认证成功后,登录通过后继续访问安全资源,再次访问安全资源时,过滤器casfilter拦截,根据用户上下文判断用户已经登录,就不再拦截安全资源,直接正常访问安全资源。而有些应用中使用其他方式处理请求,按上述常规方法不好处理,下面举实例来看看解决方案。
5.1.Ajax客户端
公司有一个应用系统使用Ajax客户端来处理请求并取得响应,在访问超时时,Ajax客户端请求由于使用异步处理技术(只局部刷新页面),不能将请求继续302重定向到SSO服务器重新认证处理,不能继续访问安全资源,界面响应处于一直延迟状态,很不友好。我们针对此应用进行适应性改造。改造要点如下:
我们约定应用系统的一个Ajax请求的标记(如ajaxRequestFlag=ajaxRequest),在安全资源ajax调用请求时携带此请求参数,还约定一个超时请求的响应状态值(如555),SSO客户端的过滤器casfilter的相应类程序对此约定进行了相应的改造。
应用系统的安全资源页面中引入文件(HttpStatusSSO.js)SSO对Axax请求的http状态的处理,其中有超时时的状态处理、判断是否登录、验证票据等的处理,都是通过ajax请求方式来处理的,其中依赖一个验证票据的资源ticketValidate.jsp。
经过上述改造后,应用系统的安全资源发送携带ajax请求标记的请求,在超时请求时,SSO客户端返回约定响应码(555),HttpStatusSSO.js文件判断处理后转发给相应的登录页面重新认证。单点登录的访问也能够正常的实现功能。这样只扩展了SSO客户端组件的实现,向下版本兼容,保证了SSO组件的统一完整性。
上述改造方式是通过实践开发出来的,可能还有更好的方法来改造扩展,今后持续改进吧。
后记:现在官方的CAS源码3.4版本已经支持Ajax请求的客户端,它的实现机制有待于进一步的研究,大家可以参考。
5.2.多域认证
有时我们遇到,不同子系统的认证实现的数据源可能来自一个用户数据库。我公司就是这种情况,采用Saas模式运营的软件,认证的用户来源于不同的租户或者域,基于这样的情况,我们对SSO进行了扩展,主要提供了认证接口,认证实现上,可以在认证时动态取得租户对应的数据源,对用户进行认证处理。举例如下:
5.3.SSO集中认证登录页面需要在业务子系统中定制
SSO集中认证的登录页面默认是放在SSO服务器端的,样式也很不好看,用户需要把登录页面放在业务子系统中自行定制,我们对SSO进行了扩展,思路也很简单,主要是将显示默认登录页面的调用,变成了远程调用业务子系统的页面地址,这个地址可以作为配置参数来配置。举例如下
评论
1 楼
rockethj8
2015-09-14
client 㓟有一个参数是可以忽略一些URL 不进行验证登录的,不要重新源码
ignorePattern Defines the url pattern to ignore, when intercepting authentication requests.
我用的是4.0
文档:
https://github.com/Jasig/java-cas-client/blob/master/README.md
ignorePattern Defines the url pattern to ignore, when intercepting authentication requests.
我用的是4.0
文档:
https://github.com/Jasig/java-cas-client/blob/master/README.md
发表评论
-
sso 之 搜狐单点登陆实现方案
2013-09-11 23:42 1487http://blog.chinaunix.net/uid-2 ... -
淘宝如何跨域获取 Cookie 分析
2013-08-24 11:36 1206淘宝如何跨域获取 Cookie 分析 http://denge ... -
sso 入门
2013-07-08 00:53 917http://www.cnblogs.com/kingcucu ... -
SSO(单点登录)实现机制讲解
2013-07-08 00:49 1482http://blog.csdn.net/yan_dk/art ... -
sso 之 CAS 之 跨域 Ajax 登录实践
2013-07-07 02:01 0http://www.iteye.com/topic/1111 ... -
sso 之 新浪微博如何实现 SSO
2013-07-07 02:00 0http://www.iteye.com/topic/1039 ... -
sso 之 用CAS实现SSO----简单tomcat实例配置
2013-07-07 01:46 0http://mljavalife.iteye.com/blo ... -
sso 之 详细设计说明书(下篇)
2013-07-07 01:41 1488http://cailin.iteye.com/blog/14 ... -
SSO单点登录解决方案
2013-07-07 01:01 1165http://www.blogjava.net/Jack200 ... -
ss0 之 cas改造随笔
2013-07-07 00:53 1140http://www.sparkfood.com/2010/0 ... -
java单点登录_设计一
2012-10-31 22:56 1018http://www.blogjava.net/ ...
相关推荐
在本文中,我们将深入探讨如何利用CAS实现单点登录功能,这将涉及到以下几个关键知识点: 1. **单点登录(SSO)原理**: SSO允许用户在一个应用系统中登录后,无需再次验证身份即可访问其他相互信任的应用系统。...
单点登录(Single Sign-On,简称SSO)是一种网络用户身份验证的机制,它允许用户在一次登录后,就可以在多个相互独立的应用系统之间自由切换,而无需再次进行身份验证。CAS(Central Authentication Service)是耶鲁...
配置Windows单点登录主要包括以下几个关键步骤: 1. **设置活动目录域服务**:首先,需要确保你的网络环境基于Windows Server的活动目录域服务(Active Directory Domain Services, AD DS)运行。AD DS提供集中式...
在Laravel框架中实现SSO单点登录涉及到的PHP知识点可以从以下几个方面阐述: 1. Laravel框架简述:Laravel是一个基于MVC(Model-View-Controller)架构的PHP框架,它通过各种内置特性简化了Web开发流程,如路由...
SharePoint SSO(Single Sign-On,单点登录)是一种安全机制,它允许用户在访问多个应用系统时只需要登录一次,从而提高工作效率并简化安全管理。在SharePoint环境中,SSO是企业级集成的关键部分,尤其在拥有多种...
单点登录(Single Sign-On,简称SSO)是一种网络身份验证机制,允许用户在一个系统上登录后,无需重新认证即可访问多个相互独立的应用系统。它极大地提升了用户体验,减少了记忆和输入多个用户名和密码的繁琐,同时...
《DSMP规范SSO分册》是一份详细阐述单点登录(Single Sign-On,简称SSO)在DSMP(Data Service Management Platform,数据服务平台)规范中的应用和实施指南。SSO是现代企业信息化系统中常见的一种身份认证机制,它...
理解并掌握以上知识点,将有助于你成功地在Tomcat环境中实施CAS单点登录。这个教程应包含详细的步骤、示例代码以及可能遇到的问题和解决方法,帮助你一步步构建起安全、高效的SSO环境。在实际操作中,可能会遇到各种...
在实施 SSO 系统之前,组织需要考虑以下几个重要的业务管理因素: 1. **需求分析**:明确组织对于 SSO 的具体需求,包括哪些应用程序和服务需要集成,以及期望达到的安全性和用户体验水平。 2. **成本效益分析**...
单点登录(SSO)允许用户在一个应用系统中登录后,无需再次认证即可访问其他相互信任的应用系统。在CAS框架下,这个过程涉及到以下几个核心概念: 1. **CAS服务器**:这是整个SSO系统的核心,负责用户的身份验证。...
为了解决传统单点登录系统在结构复杂性和灵活性上的不足,以及在实际实施中的高成本问题,本文提出了一个三层单点登录模型。该模型的主要特点在于其简单性,便于在中小企业网络环境中快速实施。三层模型的设计包括...
- **技术选型**:在选择CASserver作为单点登录方案时,可能遇到了版本兼容性问题,需要调整服务器环境。 - **框架整合**:在集成不同框架的过程中遇到了问题,可能是因为不同的框架之间存在依赖关系或者配置冲突。 -...
5. **单点登录(Single Sign-On, SSO)**: 若系统复杂,可考虑采用SSO技术,如CAS(Central Authentication Service)或OAuth,实现更高效的身份验证管理。 在提供的文件列表中,"www.site.com"和"www.php7.com"可能...
CAS客户端3.1.3是针对企业或组织的IT系统设计的一款重要的身份验证工具,它主要实现了单点登录(Single Sign-On, SSO)功能。SSO是一种让用户在多个相关应用系统间进行无缝切换,只需一次登录即可访问所有资源的技术...
在`org.jasig.cas.client.util`包下新增几个工具类,以辅助实现内外网访问的功能。 - `PropertiesUtil`: 用于读取配置文件中的属性值。 - `HttpConnectionUtil`: 处理HTTP连接相关的操作。 - `CustomConfigUtil...
这个项目可能是为了展示如何在Spring Boot应用程序中整合CAS(Central Authentication Service)客户端,以便实现单点登录(Single Sign-On, SSO)功能。 【描述】中的关键信息表明,这个"cas_client"是基于Spring ...
在技术层面,统一身份认证平台可能涉及单点登录(Single Sign-On, SSO)技术,通过集中式的身份验证机制,用户只需要提供一次凭证就能访问所有关联的系统。 建设统一身份认证平台的过程中,需要注意几个关键问题:...
在使用JSP开发的Web应用中,开发者可能会遇到一个令人困惑的问题:当用户使用Firefox浏览器时,基于Session的单点登录(Single Sign-On, SSO)功能表现正常;然而,切换至IE6浏览器时,初始阶段一切正常,但进行几次...
在实施SSO for WordPress时,开发者或管理员需要考虑以下几个关键知识点: 1. **身份验证协议**:SSO解决方案可能基于OAuth、OpenID Connect或SAML等标准,理解这些协议的工作原理对于配置和集成至关重要。 2. **...