天天看點

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在擷取參數時出現編碼問題。