一.问题在哪?

在配置cas-client中,有这么一段配置:

    <filter>
<filter-name>CAS Filter</filter-name>
<filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
<init-param>
<param-name>casServerLoginUrl</param-name>
<param-value>https://demo.testcas.com/cas/login</param-value>
</init-param>
<init-param>
<param-name>serverName</param-name>
<param-value>http://app1.testcas.com</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CAS Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

详情请参考:单点登录CAS使用记(二):部署CAS服务器以及客户端

意思大概是:拦截客户端的所有请求,如果发现还没有通过CAS认证中心认证,则强行重定向到Cas-server的登录页面。

二.如何解决?

2.1 百度下大多数的解决方案

扩展CASFilter过滤器,加上一个排除指定URL的功能,然后在web.xml配置中,手动添加需要排除的所有URL。

这确是一种解决方法,但是过于繁琐,而且在网站请求地址过多的情况下,稍有不慎,就会出现遗漏。

如果这是你想要的,请另行百度。

2.2 我的解决方案:

因为我是要整合两个比较成熟的项目,换言之,就是这两个项目已经自带了用户登录验证、用户权限验证、不拦截静态资源等处理。

所以我是不是可以利用原有项目的拦截逻辑?

注意上文红色描述,所以,我只要稍微改造一下原有项目的拦截器,让他不是直接跳转到原有登录页面,跳转到一个特定的请求地址,让cas-filter拦截只拦截这一个请求就可以了。

三.改造验证

第一步:修改原有项目拦截器

项目中,有这么一段SpringMVC拦截器配置(伪代码展示)

    <mvc:interceptors>
<bean class="com.xxxx.interceptor.SecurityInterceptor">
<property name="redirectUrl">
<value>/login</value>
</property>
       ...
</bean>
</mvc:interceptors>

意思就是,一旦拦截到用户未登录,直接跳转到doLogin方法,让用户登录。

我对他修改如下:

    <mvc:interceptors>
<bean class="com.xxxx.interceptor.SecurityInterceptor">
<property name="redirectUrl">
<value>/casLogin</value>
</property>
       ...
</bean>
</mvc:interceptors>

意思就是:一旦拦截到用户未登录,跳转到doCasLogin方法

第二步:新增casLogin方法

    @RequestSecurity
@RequestMapping(value = "casLogin", method = { RequestMethod.GET,
RequestMethod.POST })
public String casLogin()
{
return "welcome";
}

意思就是:如果用户未登录,会被强制重定向到本方法。

第三步:修改cas-client的拦截器Cas-Filter的拦截范围

    <filter>
<filter-name>CAS Filter</filter-name>
<filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
<init-param>
<param-name>casServerLoginUrl</param-name>
<param-value>https://demo.testcas.com/cas/login</param-value>
</init-param>
<init-param>
<param-name>serverName</param-name>
<param-value>http://app1.testcas.com</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CAS Filter</filter-name>
<url-pattern>/casLogin</url-pattern>
</filter-mapping>

意思就是:CAS Filter只拦截casLogin请求,其他请求一律不拦截。一旦拦截到casLogin请求,说明用户暂未登录,则强制重定向到Cas-Server的登录页面。

到这里,Cas-client不拦截静态资源处理就改造好了。

 

但是,如果只做上面3步,进行测试的话,浏览器有可能会报“此页面包含重定向循环”的错误提示,并不能真正登入页面。

原因看以下流程:

1.首先被重定向到了Cas认证中心

2.用户输入用户名密码等,点击登录通过了Cas登陆认证

3.再一次被重定向回/casLogin,

4.又被Cas-Fliter拦截,不过此时Cas-Fliter发现用户已经通过了Cas认证中心认证,不做重定向处理,继续后续处理。

5.因为casLogin方法标注了@RequestSecurity,所以又被原有项目的mvc:interceptors拦截,拦截器发现用户未登录(通过session是否为空来判断)

6.又被强行重定向会casLogin,然后又回到了4,陷入了无穷的循环中...

如何打破此重定向循环?

关键在于第5步,当Cas-Server重定向回来时,会带回通过认证的用户信息。

取得方式如下:

AttributePrincipal principal = (AttributePrincipal) request.getUserPrincipal();
String username = principal.getName();

这时,在过滤器判断用户是否已经登录前,先行判断如果是Cas-server重定向过来的请求,并且principal、username存在,则把用户信息写入客户端UserSession中。

然后再判断发现,已经写入了UserSession了,说明登录成功,直接登录welcome页面。

登录成功。

注:本文所记录的是自己摸索所得,并不敢完全保证程序逻辑的严谨性,如果您发现有所纰漏,请给予批评指正。


单点登录CAS使用记系列:

04-25 07:55