1. 程式人生 > >cas單點登入環境搭建

cas單點登入環境搭建

公司最近想做一個類似單點登入功能的專案,考慮用cas還是用memcache達到單點登入功能。自己以前搭過cas+shiro的環境,記憶已有些模糊。重新搭一下cas的環境,遇到了一些問題,寫下來,希望能幫到某些人,也留著以後忘記的時候,拿來看看。以下是一些步驟,網上也有很多類似的文章,都大同小異:

一  環境準備

在本機安裝jdk(安裝方法網上很多,如:http://www.blogjava.net/jackyfoo/archive/2007/01/20/95034.html),搭建tomcat(本人6.0以上)環境。從cas官網下載cas服務端(下載地址:http://downloads.jasig.org/cas/cas-server-3.5.2-release.zip)

二 設定證書

    在cas服務端的機器上,通過jdk自帶的keytool生成證書,如下:

  keytool -genkey -alias caskey -keyalg RSA -keystore d:\keys\caskey.keystore (其中caskey為別名,把證書caskey.keystore儲存到d:\keys目錄下)

  

(注意,圖的檔案命名跟上面給出的檔名字不一樣)

  匯出證書

  keytool -export -trustcacerts -file d:\keys\caskey.crt -alias caskey-keystore d:\keys\caskey

.keystore (匯出證書caskey.crtd:\keys\目錄下


  (注意,圖的檔案命名跟上面給出的檔名字不一樣)

匯入證書到cas客戶端(本人服務端和客戶端都在一臺機器上,首先命令視窗要到jre的指定目錄下,本機為:C:\Program Files\Java\jdk1.6.0_20\jre\lib\security),如:

   keytool -import -trustcacerts -keystore cacerts -file d:\keys\caskey.crt -alias caskey-storepass changeit (其中changeit這個密碼為固定,不能改

)


(注意,圖的檔案命名跟上面給出的檔名字不一樣)

三、開啟服務端Tomcat的SSL連線服務(注意:確保Tomcat所用的JDK和之前所匯入證書的JDK是相同的,有的eclipse中的tomcat是用的eclipse自帶的jdk的,這個要區分好的,因為本人剛開始跑應用的時候用的是eclipse的jetty外掛,用的jdk不是本機的jdk,當回撥的時候丟擲java.security.cert.CertificateException: No name matching www.casserver.com found異常,www.casserver.com為本人cas服務端的域名

修改Tomcat的conf下面server.xml檔案,去掉以下程式碼的註釋,然後新增你自己的keystore

<Connector port="8443" protocol="org.apache.coyote.http11.Http11Protocol" SSLEnabled="true"
               maxThreads="150" scheme="https" secure="true"
               clientAuth="false" sslProtocol="TLS" 
keystoreFile="d:\keys\caskey.keystore" keystorePass="123456"/> (caskey.keystore為生成的證書,123456為證書密碼)

四、部署cas服務端

        解壓cas-server-3.5.2-release.zip,複製modules下面的cas-server-webapp-3.5.2.war到tomcat的webapp下面,重新命名為cas.war,啟動tomcat後,用瀏覽器訪問https://你的域名:8443/cas就可以訪問。預設的情況下,輸入相同的使用者名稱和密碼就可以成功登入。這種需要通常都不適合使用者需求,可以修改cas專案的deployerConfigContext.xml配置檔案。在<sec:user-service id="userDetailsService">這個節點後面新增casDataSource:


註釋掉SimpleTestUsernamePasswordAuthenticationHandler,新增QueryDatabaseAuthenticationHandler:


同時,還要把需要的jar包丟進tomcat的cas專案的lib目錄下,否則,會丟擲某些類找不到的異常。這些包分別是:mysql-connector-java-5.1.15.jar(這是mysql的驅動包),commons-dbcp-1.4.jar,commons-pool-1.6.jar(這兩個是配置資料來源依賴的包),cas-server-support-jdbc-3.5.2.jar(QueryDatabaseAuthenticationHandler就在這個包裡面,預設是沒有的,可以到cas-server-3.5.2-release.zip解壓後modules目錄下拷貝。

五、配置客戶端(即應用系統)

本人的專案用的是maven管理,只要把依賴加進去就可以,依賴如下:

<dependency>
<groupId>org.jasig.cas.client</groupId>
<artifactId>cas-client-core</artifactId>
<version>3.2.1</version>
</dependency>

在應用系統有web.xml做以下配置:

<!-- 該過濾器用於實現單點登出功能,可選配置。 -->  
    <filter>  
        <filter-name>CAS Single Sign Out Filter</filter-name>  
        <filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>  
    </filter>  
    <filter-mapping>  
        <filter-name>CAS Single Sign Out Filter</filter-name>  
        <url-pattern>/*</url-pattern>  
    </filter-mapping>  
  
    <!-- 該過濾器負責使用者的認證工作,必須啟用它 -->  
    <filter>  
        <filter-name>CASFilter</filter-name>  
        <filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>  
        <init-param>  
            <param-name>casServerLoginUrl</param-name>  
            <param-value>https://www.casserver.com:8443/cas/login</param-value>  <!--  這裡是我的cas服務端的登入訪問地址-->
        </init-param>  
        <init-param>  
            <param-name>serverName</param-name>  
            <param-value>http://www.casclient1.com:8085</param-value>  <!--這裡是我的應用地址,即回撥地址-->
        </init-param>  
    </filter>  
    <filter-mapping>  
        <filter-name>CASFilter</filter-name>  
        <url-pattern>/*</url-pattern>  
    </filter-mapping>  
  
    <!-- 該過濾器負責對Ticket的校驗工作,必須啟用它 -->  
    <filter>  
        <filter-name>CAS Validation Filter</filter-name>  
        <filter-class>  
            org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter</filter-class>  
        <init-param>  
            <param-name>casServerUrlPrefix</param-name>  
            <param-value>https://www.casserver.com:8443/cas</param-value>  <!--  這裡是我的cas服務端的訪問地址-->
        </init-param>  
        <init-param>  
            <param-name>serverName</param-name>  
            <param-value>http://www.casclient1.com:8085</param-value>  <!--這裡是我的應用地址,即回撥地址-->
        </init-param>  
    </filter>  
    <filter-mapping>  
        <filter-name>CAS Validation Filter</filter-name>  
        <url-pattern>/*</url-pattern>  
    </filter-mapping>  
  
    <!-- 該過濾器負責實現HttpServletRequest請求的包裹, 比如允許開發者通過HttpServletRequest的getRemoteUser()方法獲得SSO登入使用者的登入名,可選配置。 -->  
    <filter>  
        <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>  
        <filter-class>  
            org.jasig.cas.client.util.HttpServletRequestWrapperFilter</filter-class>  
    </filter>  
    <filter-mapping>  
        <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>  
        <url-pattern>/*</url-pattern>  
    </filter-mapping>  
  
    <!-- 該過濾器使得開發者可以通過org.jasig.cas.client.util.AssertionHolder來獲取使用者的登入名。 比如AssertionHolder.getAssertion().getPrincipal().getName()。 -->  
    <filter>  
        <filter-name>CAS Assertion Thread Local Filter</filter-name>  
        <filter-class>org.jasig.cas.client.util.AssertionThreadLocalFilter</filter-class>  
    </filter>  
    <filter-mapping>  
        <filter-name>CAS Assertion Thread Local Filter</filter-name>  
        <url-pattern>/*</url-pattern>  
    </filter-mapping>  

以上的配置網路上很容易找到。同時,可以修改系統的hosts檔案(C:\WINDOWS\system32\drivers\etc\hosts),設定域名,我的hosts檔案如下:


到這裡,cas單點登入基本部署完成了。使用者可以訪問,www.casclient1.com,當未登入的時候,會跳轉到www.casserver.com(cas服務端)進行登入認證,認證通過後,回撥到www.casclient1.com上。

本人理解的單點登入流程大概如下:

首先使用者訪問應用,應用配置了cas的filter,filter攔截,根據web.xml的配置地址,然後定向到cas服務端上,cas服務端檢查使用者的cookie,發現使用者沒曾登入,就顯示登入頁面讓使用者登入認證。認證通過後,cas往使用者的客戶端寫加密的cookie,然後回撥到使用者實際訪問的應用地址。如果發現使用者已經登入,就直接回調到使用者實際訪問的應用地址,而無需使用者再登入。無論使用者是否登入過,都要經過cas服務端,再進行回撥。

       以上cas的配置方式跟網上的大同小異,不過加入了本人遇到的一些問題,希望能幫遇到同樣問題的人更好理解。也因本人知識有限,如有不對,希望指正。

補充:

通常我們新增使用者的時候,密碼都是通過加密了的,這樣,對登入的輸入密碼也要加密,才能和資料庫的密碼進行匹配。看了一下QueryDatabaseAuthenticationHandler(在cas-server-support-jdbc.jar包下)的原碼,在對密碼的匹配時,呼叫了getPasswordEncoder()方法來對輸入密碼進行加密。原始碼如下:


顯然getPasswordEncoder()方法是在父類定義的,通過跟程式碼,可以看到在cas-server-core.jar包下的AbstractUsernamePasswordAuthenticationHandler類中定義,程式碼如下:


該類中預設使用了PlainTextPasswordEncoder類來進行加密,但PlainTextPasswordEncoder這個類的是對密碼沒有任何加密動作,直接返回密碼的,程式碼如下:


所有,只要自己寫一個Encoder,替換PlainTextPasswordEncoder,就能達到自己加密方法的效果。自己的Encoder程式碼如下:


其中,用的是commons-codec.jar包下的DigestUtils進行加密。當然,加密方法必須和儲存到資料庫的密碼加密方法一致。

然後,修改cas專案的deployerConfigContext.xml配置檔案。新增自己的Encoder:

<bean id="passwordEncode" class="com.cas.encode.passwordencode.MD5Encoder"/> 

把encoder注入到QueryDatabaseAuthenticationHandler中

<bean class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler">  
<property name="dataSource" ref="casDataSource" />  
<property name="sql" value="select password from user where username = ?" /> 
<property name="passwordEncoder" ref="passwordEncode" /> 
</bean>

這樣,加密方式就起作用。

2013.7.31