Cas(07)——建立使用Cas進行單點登錄的應用

建立使用Cas進行單點登錄的應用

 

目錄

1.1加入cas-client-core-xxx.jarclasspath

1.2配置Filter

1.2.1AuthenticationFilter

1.2.2TicketValidationFilter

1.2.3HttpServletRequestWrapperFilter

1.2.4AssertionThreadLocalFilter

1.2.5基於SpringFilter配置

1.3添加證書到信任庫

 

       根據之前的描述我們知道,Cas由兩部分組成,Cas ServerCas ClientCas ServerCas自己的服務端,而Cas ClientCas客戶端,其需要與我們自己的應用進行集成。

 

1.1     加入cas-client-core-xxx.jarclasspath

       在我們下載的Cas Client壓縮包的modules目錄下可以找到一個名爲cas-client-core-xxx.jarjar文件,首先需要將該jar包加入我們應用的類路徑下,筆者這裏使用的是cas-client-core-3.1.11.jar。如果用戶的應用是使用Maven構造的,則可以在應用的pom.xml文件中加入如下依賴。

   <dependency>

      <groupId>org.jasig.cas.client</groupId>

      <artifactId>cas-client-core</artifactId>

      <version>3.1.11</version>

   </dependency>

 

1.2     配置Filter

       然後需要我們在應用的web.xml文件中配置四個Filter,這四個Filter必須按照固定的順序來進行配置,而且它們必須配置在應用的其它Filter之前。它們的先後順序要求如下:

l  AuthenticationFilter

l  TicketValidationFilter

l  HttpServletRequestWrapperFilter

l  AssertionThreadLocalFilter

 

       這些Filter有的必須指定某些參數,有的可以指定某些參數,這些參數可以通過context-param來指定,也可以通過init-param來指定。Cas Client默認會先從init-param取,沒取到則從context-param取,所以當init-paramcontext-param都指定了某個參數時,init-param指定的將擁有更高的優先級。所以當多個Filter需要共用一個參數時,我們可以把它定義爲context-param

 

1.2.1    AuthenticationFilter

       AuthenticationFilter用來攔截所有的請求,用以判斷用戶是否需要通過Cas Server進行認證,如果需要則將跳轉到Cas Server的登錄頁面。如果不需要進行登錄認證,則請求會繼續往下執行。

     AuthenticationFilter有兩個用戶必須指定的參數,一個是用來指定Cas Server登錄地址的casServerLoginUrl,另一個是用來指定認證成功後需要跳轉地址的serverNameserviceserviceserverName只需要指定一個就可以了。當兩者都指定了,參數service將具有更高的優先級,即將以service指定的參數值爲準。serviceserverName的區別在於service指定的是一個確定的URL,認證成功後就會確切的跳轉到service指定的URL;而serverName則是用來指定主機名,其格式爲{protocol}:{hostName}:{port},如:https://localhost:8443,當指定的是serverName時,AuthenticationFilter將會把它附加上當前請求的URI,以及對應的查詢參數來構造一個確定的URL,如指定serverName爲“http://localhost”,而當前請求的URI爲“/app”,查詢參數爲“a=b&b=c”,則對應認證成功後的跳轉地址將爲“http://localhost/app?a=b&b=c”。

 

       除了上述必須指定的參數外,AuthenticationFilter還可以指定如下可選參數:

l  renew:當指定renewtrue時,在請Cas Server時將帶上參數“renew=true”,默認爲false

l  gateway:指定gatewaytrue時,在請求Cas Server時將帶上參數“gateway=true”,默認爲false

l  artifactParameterName:指定ticket對應的請求參數名稱,默認爲ticket

l  serviceParameterName:指定service對應的請求參數名稱,默認爲service

 

       如下是一個配置AuthenticationFilter的示例,serverName由於在接下來配置的Filter中還要用,所以利用context-param將其配置爲一個公用的參數。“elim”對應我的電腦名。

 

   <context-param>

      <param-name>serverName</param-name>

      <param-value>http://elim:8080</param-value>

   </context-param>

  

   <filter>

      <filter-name>casAuthenticationFilter</filter-name>

   <filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>

      <init-param>

         <param-name>casServerLoginUrl</param-name>

         <param-value>https://elim:8443/cas/login</param-value>

      </init-param>

   </filter>

   <filter-mapping>

      <filter-name>casAuthenticationFilter</filter-name>

      <url-pattern>/*</url-pattern>

   </filter-mapping>

 

1.2.2    TicketValidationFilter

       在請求通過AuthenticationFilter的認證之後,如果請求中攜帶了參數ticket則將會由TicketValidationFilter來對攜帶的ticket進行校驗。TicketValidationFilter只是對驗證ticket的這一類Filter的統稱,其並不對應Cas Client中的一個具體類型。Cas Client中有多種驗證ticketFilter,都繼承自AbstractTicketValidationFilter,它們的驗證邏輯都是一致的,都有AbstractTicketValidationFilter實現,所不同的是使用的TicketValidator不一樣。筆者這裏將以Cas10TicketValidationFilter爲例,其它還有Cas20ProxyReceivingTicketValidationFilterSaml11TicketValidationFilter

 

   <filter>

      <filter-name>casTicketValidationFilter</filter-name>

   <filter-class>org.jasig.cas.client.validation.Cas10TicketValidationFilter</filter-class>

      <init-param>

         <param-name>casServerUrlPrefix</param-name>

         <param-value>https://elim:8443/cas</param-value>

      </init-param>

   </filter>

   <filter-mapping>

      <filter-name>casTicketValidationFilter</filter-name>

      <url-pattern>/*</url-pattern>

   </filter-mapping>

 

       必須指定的參數:

l  casServerUrlPrefix:用來指定Cas Server對應URL地址的前綴,如上面示例的“https://elim:8443/cas”。

l  serverNameservice:語義跟前面介紹的一致。

 

       可選參數:

l  redirectAfterValidation :表示是否驗證通過後重新跳轉到該URL,但是不帶參數ticket,默認爲true

l  useSession :在驗證ticket成功後會生成一個Assertion對象,如果useSessiontrue,則會將該對象存放到Session中。如果爲false,則要求每次請求都需要攜帶ticket進行驗證,顯然useSessionfalseredirectAfterValidationtrue是衝突的。默認爲true

l  exceptionOnValidationFailure :表示ticket驗證失敗後是否需要拋出異常,默認爲true

l  renew:當值爲true時將發送“renew=true”到Cas Server,默認爲false

 

1.2.3    HttpServletRequestWrapperFilter

       HttpServletRequestWrapperFilter用於將每一個請求對應的HttpServletRequest封裝爲其內部定義的CasHttpServletRequestWrapper,該封裝類將利用之前保存在Sessionrequest中的Assertion對象重寫HttpServletRequestgetUserPrincipal()getRemoteUser()isUserInRole()方法。這樣在我們的應用中就可以非常方便的從HttpServletRequest中獲取到用戶的相關信息。以下是一個配置HttpServletRequestWrapperFilter的示例:

   <filter>

      <filter-name>casHttpServletRequestWrapperFilter</filter-name>

   <filter-class>org.jasig.cas.client.util.HttpServletRequestWrapperFilter</filter-class>

   </filter>

   <filter-mapping>

      <filter-name>casHttpServletRequestWrapperFilter</filter-name>

      <url-pattern>/*</url-pattern>

   </filter-mapping>

 

1.2.4    AssertionThreadLocalFilter

       AssertionThreadLocalFilter是爲了方便用戶在應用的其它地方獲取Assertion對象,其會將當前的Assertion對象存放到當前的線程變量中,那麼以後用戶在程序的任何地方都可以從線程變量中獲取當前Assertion,無需再從Sessionrequest中進行解析。該線程變量是由AssertionHolder持有的,我們在獲取當前的Assertion時也只需要通過AssertionHoldergetAssertion()方法獲取即可,如:

   Assertion assertion = AssertionHolder.getAssertion();

 

       AssertionThreadLocalFilter這種設計理念是非常好的,實際應用中使用的也比較多,Spring Security中也有用到這種理念。爲了便於大家瞭解,特貼出AssertionHolder的源碼如下:

public class AssertionHolder {

 

    /**

     * ThreadLocal to hold the Assertion for Threads to access.

     */

    private static final ThreadLocal threadLocal = new ThreadLocal();

 

 

    /**

     * Retrieve the assertion from the ThreadLocal.

     */

    public static Assertion getAssertion() {

        return (Assertion) threadLocal.get();

    }

 

    /**

     * Add the Assertion to the ThreadLocal.

     */

    public static void setAssertion(final Assertion assertion) {

        threadLocal.set(assertion);

    }

 

    /**

     * Clear the ThreadLocal.

     */

    public static void clear() {

        threadLocal.set(null);

    }

}

 

       以下是配置AssertionThreadLocalFilter的示例:

   <filter>

      <filter-name>casAssertionThreadLocalFilter</filter-name>

     <filter-class>org.jasig.cas.client.util.AssertionThreadLocalFilter</filter-class>

   </filter>

   <filter-mapping>

      <filter-name>casAssertionThreadLocalFilter</filter-name>

      <url-pattern>/*</url-pattern>

   </filter-mapping>

 

1.2.5    基於Spring的Filter配置

       使用Cas單點登錄的應用需要我們在應用的web.xml文件中配置上述介紹的四個Filter,但如果用戶的應用是使用Spring開發的,則我們可以只在web.xml文件中配置四個SpringDelegatingFilterProxy用來代理需要配置的四個Filter,對應的Filter名稱對應我們需要代理的Spring ApplicationContextbean的名稱,此時我們需要將對應的Filter配置爲Spring ApplicationContext中的一個bean對象。所以此時對應的web.xml文件的定義應該是這樣的:

   <filter>

      <filter-name>casAuthenticationFilter</filter-name>

     <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>

   </filter>

   <filter-mapping>

      <filter-name>casAuthenticationFilter</filter-name>

      <url-pattern>/*</url-pattern>

   </filter-mapping>

 

   <filter>

      <filter-name>casTicketValidationFilter</filter-name>

     <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>

   </filter>

   <filter-mapping>

      <filter-name>casTicketValidationFilter</filter-name>

      <url-pattern>/*</url-pattern>

   </filter-mapping>

 

   <filter>

      <filter-name>casHttpServletRequestWrapperFilter</filter-name>

     <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>

   </filter>

   <filter-mapping>

      <filter-name>casHttpServletRequestWrapperFilter</filter-name>

      <url-pattern>/*</url-pattern>

   </filter-mapping>

 

   <filter>

      <filter-name>casAssertionThreadLocalFilter</filter-name>

     <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>

   </filter>

   <filter-mapping>

      <filter-name>casAssertionThreadLocalFilter</filter-name>

      <url-pattern>/*</url-pattern>

   </filter-mapping>

 

       而對應的Filter應該都以對應的名稱定義爲Spring ApplicationContext中的一個bean

   <bean name="casAuthenticationFilter"

      class="org.jasig.cas.client.authentication.AuthenticationFilter"

      p:casServerLoginUrl="https://elim:8443/cas/login" p:renew="false"

      p:gateway="false" p:serverName="http://elim:8080" />

 

   <bean name="casTicketValidationFilter"

      class="org.jasig.cas.client.validation.Cas10TicketValidationFilter"

      p:serverName="http://elim:8080" p:redirectAfterValidation="true">

      <property name="ticketValidator">

         <bean class="org.jasig.cas.client.validation.Cas10TicketValidator">

            <!-- 對應於casServerUrlPrefix -->

            <constructor-arg index="0" value="https://elim:8443/cas" />

         </bean>

      </property>

   </bean>

 

   <bean id="casHttpServletRequestWrapperFilter" class="org.jasig.cas.client.util.HttpServletRequestWrapperFilter"/>

  

   <bean id="casAssertionThreadLocalFilter" class="org.jasig.cas.client.util.AssertionThreadLocalFilter"/>

 

1.3     添加證書到信任庫

       ticket驗證成功後,還需要驗證證書,這需要我們將之前建立的證書導出並添加到當前JRE的證書信任庫中,否則將驗證失敗。JRE在尋找證書時將根據當前使用的host來尋找,且會用該host匹配之前創建證書時指定的用戶名稱,如果匹配則表示找到。這也就意味着我們在創建證書時指定的用戶名稱需要是我們的host。我的機器名稱爲“elim”,我就把它作爲我的host,那麼對應的證書應該這樣創建。

keytool -genkey -keyalg RSA -alias tomcat -dname "cn=elim" -storepass changeit

 

       該語句是對我們之前介紹的keytool -genkey -alias tomcat -keyalg RSA的精寫,它已經通過相應的參數指定了對應的參數值,而不需要再與用戶交互了。如果還用之前的語句生成證書的話,那麼對應的值應該這樣填:



 

 

       之後會在用戶的對應目錄下生成一個.keystore文件。之後需要將該文件導出爲一個證書到%JAVA_HOME%/jre/lib/security目錄下,對應指令爲:

keytool -export -alias tomcat -file %JAVA_HOME%/jre/lib/security/tomcat.crt -storepass changeit

 

       之後需要將導出的tomcat.crt證書添加到運行時使用的JRE的受信任證書庫中,此時如果出現異常可將原本%JAVA_HOME%/jre/lib/security目錄下的cacerts刪除後繼續執行以下指令。

keytool -import -alias tomcat -file %JAVA_HOME%/jre/lib/security/tomcat.crt -keystore %JAVA_HOME%/jre/lib/security/cacerts -storepass changeit

 

       經過以上幾步後就可以啓用我們自己的Cas Client應用了,然後初次訪問該應用時就會跳轉到Cas Server進行登錄認證。認證成功後將跳轉到我們自己的Client應用進行ticket的驗證,驗證通過後就可以自由的訪問我們的Client應用了。

 

(注:本文是基於Cas Server3.5.2Cas Client3.1.11所寫)

(注:原創文章,轉載請註明出處。原文地址:http://haohaoxuexi.iteye.com/blog/2142631

 

 

 

  • 2b87930f-9e75-34bf-a225-088580045ce7-thumb.png
  • 大小: 10.5 KB
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章