天天看点

springSecurity+cas 单点登录

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在获取参数时出现编码问题。