1.1.1配置AuthenticationEntryPoint

       首先需要做的是将应用的登录认证入口改为使用CasAuthenticationEntryPoint。所以首先我们需要配置一个CasAuthenticationEntryPoint对应的bean,然后指定需要进行登录认证时使用该AuthenticationEntryPoint。配置CasAuthenticationEntryPoint时需要指定一个ServiceProperties,该对象主要用来描述service(Cas概念)相关的属性,主要是指定在Cas Server认证成功后将要跳转的地址。

<!-- 指定登录入口为casEntryPoint -->
<security:http  entry-point-ref="casEntryPoint">
      ...
</security:http>
 
<!-- 认证的入口 -->
<bean id="casEntryPoint"
class="org.springframework.security.cas.web.CasAuthenticationEntryPoint">
<!-- Cas Server的登录地址,elim是我的计算机名 -->
<property name="loginUrl" value="https://elim:8443/cas/login" />
<!-- service相关的属性 -->
<property name="serviceProperties" ref="serviceProperties" />
</bean>
 
<!-- 指定service相关信息 -->
<bean id="serviceProperties"class="org.springframework.security.cas.ServiceProperties">
<!-- Cas Server认证成功后的跳转地址,这里要跳转到我们的Spring Security应用,之后会由CasAuthenticationFilter处理,默认处理地址为/j_spring_cas_security_check -->
<property name="service"
value="http://elim:8080/app/j_spring_cas_security_check" />
</bean>


1.1.2配置CasAuthenticationFilter

       之后我们需要配置一个CasAuthenticationFilter,并将其放置在Filter链表中CAS_FILTER的位置,以处理Cas Server认证成功后的页面跳转,用以在Spring Security中进行认证。该Filter会将Cas Server传递过来的ticket(Cas概念)封装成一个Authentication(对应UsernamePasswordAuthenticationToken,其中ticket作为该Authentication的password),然后传递给AuthenticationManager进行认证。

<security:http entry-point-ref="casEntryPoint">
      ...
<security:custom-filter ref="casFilter" position="CAS_FILTER"/>
      ...
</security:http>
 
<bean id="casFilter"
class="org.springframework.security.cas.web.CasAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManager" />
<!-- 指定处理地址,不指定时默认将会是“/j_spring_cas_security_check” -->
<property name="filterProcessesUrl" value="/j_spring_cas_security_check"/>
</bean>




1.1.3配置AuthenticationManager

       CasAuthenticationFilter会将封装好的包含Cas Server传递过来的ticket的Authentication对象传递给AuthenticationManager进行认证。我们知道默认的AuthenticationManager实现类为ProviderManager,而ProviderManager中真正进行认证的是AuthenticationProvider。所以接下来我们要在AuthenticationManager中配置一个能够处理CasAuthenticationFilter传递过来的Authentication对象的AuthenticationProvider实现,CasAuthenticationProvider。CasAuthenticationProvider首先会利用TicketValidator(Cas概念)对Authentication中包含的ticket信息进行认证。认证通过后将利用持有的AuthenticationUserDetailsService根据认证通过后回传的Assertion对象中拥有的username加载用户对应的UserDetails,即主要是加载用户的相关权限信息GrantedAuthority。然后构造一个CasAuthenticationToken进行返回。之后的逻辑就是正常的Spring Security的逻辑了。

<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="casAuthenticationProvider"/>
</security:authentication-manager>
 
<bean id="casAuthenticationProvider"
class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
<!-- 通过username来加载UserDetails -->
<property name="authenticationUserDetailsService">
<beanclass="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
<!-- 真正加载UserDetails的UserDetailsService实现 -->
<constructor-arg ref="userDetailsService" />
</bean>
</property>
<property name="serviceProperties" ref="serviceProperties" />
<!-- 配置TicketValidator在登录认证成功后验证ticket -->
<property name="ticketValidator">
<bean class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator">
<!-- Cas Server访问地址的前缀,即根路径-->
<constructor-arg index="0" value="https:// elim:8443/cas" />
</bean>
</property>
<property name="key" value="key4CasAuthenticationProvider" />
</bean>
 
<bean id="userDetailsService"
class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
<property name="dataSource" ref="dataSource" />
</bean>

       经过以上三步配置以后,我们的Spring Security应用就已经跟Cas整合好了,可以在需要登录的时候通过Cas Server进行单点登录了。



1.2     单点登出

       Spring Security应用整合Cas Client配置单点登出功能实际和单独使用Cas Client配置单点登出功能一样,其根本都是通过配置一个SingleSignOutFilter响应Cas Server单点登出时的回调,配置一个SingleSignOutHttpSessionListener用于在Session过期时删除SingleSignOutFilter存放的对应信息。SingleSignOutFilter需要配置在Cas 的AuthenticationFilter之前,对于Spring Security应用而言,该Filter通常是配置在Spring Security的配置文件中,而且是配置在CAS_FILTER之前。所以我们可以在Spring Security的配置文件中进行如下配置。

<security:http entry-point-ref="casEntryPoint">
<!-- SingleSignOutFilter放在CAS_FILTER之前 -->
<security:custom-filter ref="casLogoutFilter" before="CAS_FILTER"/>
<security:custom-filter ref="casFilter" position="CAS_FILTER"/>
      ...
</security:http>
 
<bean id="casLogoutFilter" class="org.jasig.cas.client.session.SingleSignOutFilter"/>

 

       然后跟单独使用Cas Client一样,在web.xml文件中配置一个SingleSignOutHttpSessionListener。

<listener>
<listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
</listener>

       经过以上配置在访问Cas Server的logout地址(如:https:elim:8443/cas/logout)进行登出时,Cas Server登出后将回调其中注册的每一个Service(Cas概念,即client应用),此时在client应用中配置好的SingleSignOutFilter将处理对应Client应用的登出操作。

 

       虽然以上配置可以满足我们在Spring Security应用中的单点登出要求,但Cas官方文档和Spring Security官方文档都推荐我们在Cas Client应用进行登出操作时,不是直接访问Cas Server的logout,而是先登出本应用,然后告诉用户其当前登出的只是本应用,再提供一个对应Cas Server的链接,使其可以进行真正的单点登出。对此,Spring Security官方文档中给我们提供例子是提供两个LogoutFilter,一个是登出当前Spring Security应用,一个是登出Cas Server的。

<security:http entry-point-ref="casEntryPoint">
<!-- 请求登出Cas Server的过滤器,放在Spring Security的登出过滤器之前 -->
<security:custom-filter ref="requestCasLogoutFilter" before="LOGOUT_FILTER"/>
<!-- SingleSignOutFilter放在CAS_FILTER之前 -->
<security:custom-filter ref="casLogoutFilter" before="CAS_FILTER"/>
<security:custom-filter ref="casFilter" position="CAS_FILTER"/>
      ...
</security:http>
 
<bean id="requestCasLogoutFilter"class="org.springframework.security.web.authentication.logout.LogoutFilter">
<!-- 指定登出成功后需要跳转的地址,这里指向Cas Server的登出URL,以实现单点登出 -->
<constructor-arg value="https://elim:8443/cas/logout"/>
<constructor-arg>
<beanclass="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"/>
</constructor-arg>
<!-- 该Filter需要处理的地址,默认是Spring Security的默认登出地址“/j_spring_security_logout”-->
<property name="filterProcessesUrl" value="/j_spring_cas_security_logout"/>
</bean>

       此外,Spring Security推荐我们在使用Cas Server的单点登出时一起使用CharacterEncodingFilter,以避免SingleSignOutFilter在获取参数时出现编码问题。