使用 CAS 在 Tomcat 中實現單點登陸

單點登陸(Single Sign On , 簡稱 SSO )是目前比較流行的服務於企業業務整合的解決方案之一, SSO 使得在多個應用系統中,用戶只須要登陸一次就能夠訪問全部相互信任的應用系統。CAS(Central Authentication Service)是一款不錯的針對 Web 應用的單點登陸框架,本文介紹了 CAS 的原理、協議、在 Tomcat 中的配置和使用,對於採用 CAS 實現輕量級單點登陸解決方案的入門讀者具備必定指導做用。html

張 濤 (zzhangt@cn.ibm.com), 軟件工程師, IBMweb

關閉 [x]spring

張濤,IBM 中國軟件開發實驗室工程師,目前主要致力於基於 Rational 平臺解決方案的開發。sql



王 秉坤 (wangbk@cn.ibm.com), 軟件工程師, IBM數據庫

關閉 [x]apache

王秉坤,IBM 中國軟件開發實驗室工程師,目前主要致力於基於 Rational 平臺解決方案的開發。瀏覽器



2008 年 4 月 10 日緩存

CAS 介紹

CAS 是 Yale 大學發起的一個開源項目,旨在爲 Web 應用系統提供一種可靠的單點登陸方法,CAS 在 2004 年 12 月正式成爲 JA-SIG 的一個項目。CAS 具備如下特色:

  • 開源的企業級單點登陸解決方案。
  • CAS Server 爲須要獨立部署的 Web 應用。
  • CAS Client 支持很是多的客戶端(這裏指單點登陸系統中的各個 Web 應用),包括 Java, .Net, PHP, Perl, Apache, uPortal, Ruby 等。

CAS 原理和協議

從結構上看,CAS 包含兩個部分: CAS Server 和 CAS Client。CAS Server 須要獨立部署,主要負責對用戶的認證工做;CAS Client 負責處理對客戶端受保護資源的訪問請求,須要登陸時,重定向到 CAS Server。圖1 是 CAS 最基本的協議過程:

圖 1. CAS 基礎協議
CAS 基礎協議

CAS Client 與受保護的客戶端應用部署在一塊兒,以 Filter 方式保護受保護的資源。對於訪問受保護資源的每一個 Web 請求,CAS Client 會分析該請求的 Http 請求中是否包含 Service Ticket,若是沒有,則說明當前用戶還沒有登陸,因而將請求重定向到指定好的 CAS Server 登陸地址,並傳遞 Service (也就是要訪問的目的資源地址),以便登陸成功事後轉回該地址。用戶在第 3 步中輸入認證信息,若是登陸成功,CAS Server 隨機產生一個至關長度、惟1、不可僞造的 Service Ticket,並緩存以待未來驗證,以後系統自動重定向到 Service 所在地址,併爲客戶端瀏覽器設置一個 Ticket Granted Cookie(TGC),CAS Client 在拿到 Service 和新產生的 Ticket 事後,在第 5,6 步中與 CAS Server 進行身份合適,以確保 Service Ticket 的合法性。

在該協議中,全部與 CAS 的交互均採用 SSL 協議,確保,ST 和 TGC 的安全性。協議工做過程當中會有 2 次重定向的過程,可是 CAS Client 與 CAS Server 之間進行 Ticket 驗證的過程對於用戶是透明的。

另外,CAS 協議中還提供了 Proxy (代理)模式,以適應更加高級、複雜的應用場景,具體介紹能夠參考 CAS 官方網站上的相關文檔。

準備工做

本文中的例子以 tomcat5.5 爲例進行講解,下載地址:

http://tomcat.apache.org/download-55.cgi

到 CAS 官方網站下載 CAS Server 和 Client,地址分別爲:

http://www.ja-sig.org/downloads/cas/cas-server-3.1.1-release.zip

http://www.ja-sig.org/downloads/cas-clients/cas-client-java-2.1.1.zip


部署 CAS Server

CAS Server 是一套基於 Java 實現的服務,該服務以一個 Java Web Application 單獨部署在與 servlet2.3 兼容的 Web 服務器上,另外,因爲 Client 與 CAS Server 之間的交互採用 Https 協議,所以部署 CAS Server 的服務器還須要支持 SSL 協議。當 SSL 配置成功事後,像普通 Web 應用同樣將 CAS Server 部署在服務器上就能正常運行了,不過,在真正使用以前,還須要擴展驗證用戶的接口。

在 Tomcat 上部署一個完整的 CAS Server 主要按照如下幾個步驟:

配置 Tomcat 使用 Https 協議

若是但願 Tomcat 支持 Https,主要的工做是配置 SSL 協議,其配置過程和配置方法能夠參考 Tomcat 的相關文檔。不過在生成證書的過程當中,會有須要用到主機名的地方,CAS 建議不要使用 IP 地址,而要使用機器名或域名。

部署 CAS Server

CAS Server 是一個 Web 應用包,將前面下載的 cas-server-3.1.1-release.zip 解開,把其中的 cas-server-webapp-3.1.1.war 拷貝到 tomcat的 webapps 目錄,並改名爲 cas.war。因爲前面已配置好 tomcat 的 https 協議,能夠從新啓動 tomcat,而後訪問:https://localhost:8443/cas ,若是能出現正常的 CAS 登陸頁面,則說明 CAS Server 已經部署成功。

雖然 CAS Server 已經部署成功,但這只是一個缺省的實現,在實際使用的時候,還須要根據實際概況作擴展和定製,最主要的是擴展認證 (Authentication) 接口和 CAS Server 的界面。

擴展認證接口

CAS Server 負責完成對用戶的認證工做,它會處理登陸時的用戶憑證 (Credentials) 信息,用戶名/密碼對是最多見的憑證信息。CAS Server 可能須要到數據庫檢索一條用戶賬號信息,也可能在 XML 文件中檢索用戶名/密碼,還可能經過 LDAP Server 獲取等,在這種狀況下,CAS 提供了一種靈活但統一的接口和實現分離的方式,實際使用中 CAS 採用哪一種方式認證是與 CAS 的基本協議分離開的,用戶能夠根據認證的接口去定製和擴展。

擴展 AuthenticationHandler

CAS 提供擴展認證的核心是 AuthenticationHandler 接口,該接口定義如清單 1 下:

清單 1. AuthenticationHandler定義
public interface AuthenticationHandler {
    /**
     * Method to determine if the credentials supplied are valid.
     * @param credentials The credentials to validate.
     * @return true if valid, return false otherwise.
     * @throws AuthenticationException An AuthenticationException can contain
     * details about why a particular authentication request failed.
     */
    boolean authenticate(Credentials credentials) throws AuthenticationException;
/**
     * Method to check if the handler knows how to handle the credentials
     * provided. It may be a simple check of the Credentials class or something
     * more complicated such as scanning the information contained in the
     * Credentials object. 
     * @param credentials The credentials to check.
     * @return true if the handler supports the Credentials, false othewrise.
     */
    boolean supports(Credentials credentials);
}

該接口定義了 2 個須要實現的方法,supports ()方法用於檢查所給的包含認證信息的Credentials 是否受當前 AuthenticationHandler 支持;而 authenticate() 方法則擔當驗證認證信息的任務,這也是須要擴展的主要方法,根據狀況與存儲合法認證信息的介質進行交互,返回 boolean 類型的值,true 表示驗證經過,false 表示驗證失敗。

CAS3中還提供了對AuthenticationHandler 接口的一些抽象實現,好比,可能須要在執行authenticate() 方法先後執行某些其餘操做,那麼可讓本身的認證類擴展自清單 2 中的抽象類:

清單 2. AbstractPreAndPostProcessingAuthenticationHandler定義
public abstract class AbstractPreAndPostProcessingAuthenticationHandler 
                                           implements AuthenticateHandler{
    protected Log log = LogFactory.getLog(this.getClass());
    protected boolean preAuthenticate(final Credentials credentials) {
        return true;
    }
    protected boolean postAuthenticate(final Credentials credentials,
        final boolean authenticated) {
        return authenticated;
    }
    public final boolean authenticate(final Credentials credentials)
        throws AuthenticationException {
        if (!preAuthenticate(credentials)) {
            return false;
        }
        final boolean authenticated = doAuthentication(credentials);
        return postAuthenticate(credentials, authenticated);
    }
    protected abstract boolean doAuthentication(final Credentials credentials) 
throws AuthenticationException;
}

AbstractPreAndPostProcessingAuthenticationHandler 類新定義了 preAuthenticate() 方法和 postAuthenticate() 方法,而實際的認證工做交由 doAuthentication() 方法來執行。所以,若是須要在認證先後執行一些額外的操做,能夠分別擴展 preAuthenticate()和 ppstAuthenticate() 方法,而 doAuthentication() 取代 authenticate() 成爲了子類必需要實現的方法。

因爲實際運用中,最經常使用的是用戶名和密碼方式的認證,CAS3 提供了針對該方式的實現,如清單 3 所示:

清單 3. AbstractUsernamePasswordAuthenticationHandler 定義
public abstract class AbstractUsernamePasswordAuthenticationHandler extends 
                       AbstractPreAndPostProcessingAuthenticationHandler{
...
 protected final boolean doAuthentication(final Credentials credentials)
 throws AuthenticationException {
 return authenticateUsernamePasswordInternal((UsernamePasswordCredentials) credentials);
 }
 protected abstract boolean authenticateUsernamePasswordInternal(
        final UsernamePasswordCredentials credentials) throws AuthenticationException;   
protected final PasswordEncoder getPasswordEncoder() {
 return this.passwordEncoder;
 }
public final void setPasswordEncoder(final PasswordEncoder passwordEncoder) {
 this.passwordEncoder = passwordEncoder;
    }
...
}

基於用戶名密碼的認證方式可直接擴展自 AbstractUsernamePasswordAuthenticationHandler,驗證用戶名密碼的具體操做經過實現 authenticateUsernamePasswordInternal() 方法達到,另外,一般狀況下密碼會是加密過的,setPasswordEncoder() 方法就是用於指定適當的加密器。

從以上清單中能夠看到,doAuthentication() 方法的參數是 Credentials 類型,這是包含用戶認證信息的一個接口,對於用戶名密碼類型的認證信息,能夠直接使用 UsernamePasswordCredentials,若是須要擴展其餘類型的認證信息,須要實現Credentials接口,而且實現相應的 CredentialsToPrincipalResolver 接口,其具體方法能夠借鑑 UsernamePasswordCredentials 和 UsernamePasswordCredentialsToPrincipalResolver。

JDBC 認證方法

用戶的認證信息一般保存在數據庫中,所以本文就選用這種狀況來介紹。將前面下載的 cas-server-3.1.1-release.zip 包解開後,在 modules 目錄下能夠找到包 cas-server-support-jdbc-3.1.1.jar,其提供了經過 JDBC 鏈接數據庫進行驗證的缺省實現,基於該包的支持,咱們只須要作一些配置工做便可實現 JDBC 認證。

JDBC 認證方法支持多種數據庫,DB2, Oracle, MySql, Microsoft SQL Server 等都可,這裏以 DB2 做爲例子介紹。而且假設DB2數據庫名: CASTest,數據庫登陸用戶名: db2user,數據庫登陸密碼: db2password,用戶信息表爲: userTable,該表包含用戶名和密碼的兩個數據項分別爲 userName 和 password。

1. 配置 DataStore

打開文件 %CATALINA_HOME%/webapps/cas/WEB-INF/deployerConfigContext.xml,添加一個新的 bean 標籤,對於 DB2,內容如清單 4 所示:

清單 4. 配置 DataStore
<bean id="casDataSource" class="org.apache.commons.dbcp.BasicDataSource">
     <property name="driverClassName">
          <value>com.ibm.db2.jcc.DB2Driver</value>
     </property>
     <property name="url">
          <value>jdbc:db2://9.125.65.134:50000/CASTest</value>
     </property>
     <property name="username">
          <value>db2user</value>
     </property>
     <property name="password">
          <value>db2password</value>
     </property>
</bean>

其中 id 屬性爲該 DataStore 的標識,在後面配置 AuthenticationHandler 會被引用,另外,須要提供 DataStore 所必需的數據庫驅動程序、鏈接地址、數據庫登陸用戶名以及登陸密碼。

2. 配置 AuthenticationHandler

在 cas-server-support-jdbc-3.1.1.jar 包中,提供了 3 個基於 JDBC 的 AuthenticationHandler,分別爲 BindModeSearchDatabaseAuthenticationHandler, QueryDatabaseAuthenticationHandler, SearchModeSearchDatabaseAuthenticationHandler。其中 BindModeSearchDatabaseAuthenticationHandler 是用所給的用戶名和密碼去創建數據庫鏈接,根據鏈接創建是否成功來判斷驗證成功與否;QueryDatabaseAuthenticationHandler 經過配置一個 SQL 語句查出密碼,與所給密碼匹配;SearchModeSearchDatabaseAuthenticationHandler 經過配置存放用戶驗證信息的表、用戶名字段和密碼字段,構造查詢語句來驗證。

使用哪一個 AuthenticationHandler,須要在 deployerConfigContext.xml 中設置,默認狀況下,CAS 使用一個簡單的 username=password 的 AuthenticationHandler,在文件中能夠找到以下一行:<bean class="org.jasig.cas.authentication.handler.support.SimpleTestUsernamePassword
AuthenticationHandler" />,咱們能夠將其註釋掉,換成咱們但願的一個 AuthenticationHandler,好比,使用QueryDatabaseAuthenticationHandler 或 SearchModeSearchDatabaseAuthenticationHandler 能夠分別選取清單 5 或清單 6 的配置。

清單 5. 使用 QueryDatabaseAuthenticationHandler
<bean class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler">
 <property name="dataSource" ref=" casDataSource " />
 <property name="sql" 
       value="select password from userTable where lower(userName) = lower(?)" />
</bean>
清單 6. 使用 SearchModeSearchDatabaseAuthenticationHandler
<bean id="SearchModeSearchDatabaseAuthenticationHandler"
      class="org.jasig.cas.adaptors.jdbc.SearchModeSearchDatabaseAuthenticationHandler"
      abstract="false" singleton="true" lazy-init="default" 
                       autowire="default" dependency-check="default">
  <property  name="tableUsers">
   <value>userTable</value>
  </property>
  <property name="fieldUser">
   <value>userName</value>
  </property>
  <property name="fieldPassword">
   <value>password</value>
  </property>
  <property name="dataSource" ref=" casDataSource " />
</bean>

另外,因爲存放在數據庫中的密碼一般是加密過的,因此 AuthenticationHandler 在匹配時須要知道使用的加密方法,在 deployerConfigContext.xml 文件中咱們能夠爲具體的 AuthenticationHandler 類配置一個 property,指定加密器類,好比對於 QueryDatabaseAuthenticationHandler,能夠修改如清單7所示:

清單 7. 添加 passwordEncoder
<bean class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler">
  <property name="dataSource" ref=" casDataSource " />
  <property name="sql" 
           value="select password from userTable where lower(userName) = lower(?)" />
  <property  name="passwordEncoder"  ref="myPasswordEncoder"/>
</bean>

其中 myPasswordEncoder 是對清單 8 中設置的實際加密器類的引用:

清單 8. 指定具體加密器類
<bean id="passwordEncoder" 
            class="org.jasig.cas.authentication.handler.MyPasswordEncoder"/>

這裏 MyPasswordEncoder 是根據實際狀況本身定義的加密器,實現 PasswordEncoder 接口及其 encode() 方法。

3. 部署依賴包

在以上配置完成之後,須要拷貝幾個依賴的包到 cas 應用下,包括:

  • 將 cas-server-support-jdbc-3.1.1.jar 拷貝到 %CATALINA_HOME%/webapps/cas/ WEB-INF/lib 目錄。
  • 數據庫驅動,因爲這裏使用 DB2,將 %DB2_HOME%/java 目錄下的 db2java.zip (改名爲 db2java.jar), db2jcc.jar, db2jcc_license_cu.jar 拷貝到 %CATALINA_HOME%/webapps/cas/WEB-INF/lib 目錄。對於其餘數據庫,一樣將相應數據庫驅動程序拷貝到該目錄。
  • DataStore 依賴於 commons-collections-3.2.jar, commons-dbcp-1.2.1.jar, commons-pool-1.3.jar,須要到 apache 網站的 Commons 項目下載以上 3 個包放進 %CATALINA_HOME%/webapps/cas/WEB-INF/lib 目錄。

擴展 CAS Server 界面

CAS 提供了 2 套默認的頁面,分別爲「 default 」和「 simple 」,分別在目錄「 cas/WEB-INF/view/jsp/default 」和「 cas/WEB-INF/view/jsp/simple 」下。其中 default 是一個稍微複雜一些的頁面,使用 CSS,而 simple 則是能讓 CAS 正常工做的最簡化的頁面。

在部署 CAS 以前,咱們可能須要定製一套新的 CAS Server 頁面,添加一些個性化的內容。最簡單的方法就是拷貝一份 default 或 simple 文件到「 cas/WEB-INF/view/jsp 」目錄下,好比命名爲 newUI,接下來是實現和修改必要的頁面,有 4 個頁面是必須的:

  • casConfirmView.jsp: 當用戶選擇了「 warn 」時會看到的確認界面
  • casGenericSuccess.jsp: 在用戶成功經過認證而沒有目的Service時會看到的界面
  • casLoginView.jsp: 當須要用戶提供認證信息時會出現的界面
  • casLogoutView.jsp: 當用戶結束 CAS 單點登陸系統會話時出現的界面

CAS 的頁面採用 Spring 框架編寫,對於不熟悉 Spring 的使用者,在修改以前須要熟悉該框架。

頁面定製完事後,還須要作一些配置從而讓 CAS 找到新的頁面,拷貝「 cas/WEB-INF/classes/default_views.properties 」,重命名爲「 cas/WEB-INF/classes/ newUI_views.properties 」,並修改其中全部的值到相應新頁面。最後是更新「 cas/WEB-INF/cas-servlet.xml 」文件中的 viewResolver,將其修改成如清單 9 中的內容。

清單 9. 指定 CAS 頁面
<bean id="viewResolver" 
     class="org.springframework.web.servlet.view.ResourceBundleViewResolver" p:order="0">
    <property name="basenames">
        <list>
            <value>${cas.viewResolver.basename}</value>
            <value> newUI_views</value>
        </list>
    </property>
</bean>

部署客戶端應用

單點登陸的目的是爲了讓多個相關聯的應用使用相同的登陸過程,本文在講解過程當中構造 2個簡單的應用,分別以 casTest1 和 casTest2 來做爲示例,它們均只有一個頁面,顯示歡迎信息和當前登陸用戶名。這 2 個應用使用同一套登陸信息,而且只有登陸過的用戶才能訪問,經過本文的配置,實現單點登陸,即只需登陸一次就能夠訪問這兩個應用。

與 CAS Server 創建信任關係

假設 CAS Server 單獨部署在一臺機器 A,而客戶端應用部署在機器 B 上,因爲客戶端應用與 CAS Server 的通訊採用 SSL,所以,須要在 A 與 B 的 JRE 之間創建信任關係。

首先與 A 機器同樣,要生成 B 機器上的證書,配置 Tomcat 的 SSL 協議。其次,下載http://blogs.sun.com/andreas/entry/no_more_unable_to_find 的 InstallCert.java,運行「 java InstallCert compA:8443 」命令,而且在接下來出現的詢問中輸入 1。這樣,就將 A 添加到了 B 的 trust store 中。若是多個客戶端應用分別部署在不一樣機器上,那麼每一個機器都須要與 CAS Server 所在機器創建信任關係。

配置 CAS Filter

準備好應用 casTest1 和 casTest2 事後,分別部署在 B 和 C 機器上,因爲 casTest1 和casTest2,B 和 C 徹底等同,咱們以 casTest1 在 B 機器上的配置作介紹,假設 A 和 B 的域名分別爲 domainA 和 domainB。

將 cas-client-java-2.1.1.zip 更名爲 cas-client-java-2.1.1.jar 並拷貝到 casTest1/WEB-INF/lib目錄下,修改 web.xml 文件,添加 CAS Filter,如清單 10 所示:

清單 10. 添加 CAS Filter
<web-app>
  ...
  <filter>
    <filter-name>CAS Filter</filter-name>
    <filter-class>edu.yale.its.tp.cas.client.filter.CASFilter</filter-class>
    <init-param>
      <param-name>edu.yale.its.tp.cas.client.filter.loginUrl</param-name>
      <param-value>https://domainA:8443/cas/login</param-value>
    </init-param>
    <init-param>
      <param-name>edu.yale.its.tp.cas.client.filter.validateUrl</param-name>
      <param-value>https://domainA:8443/cas/serviceValidate</param-value>
    </init-param>
    <init-param>
      <param-name>edu.yale.its.tp.cas.client.filter.serverName</param-name>
      <param-value>domainB:8080</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>CAS Filter</filter-name>
    <url-pattern>/protected-pattern/*</url-pattern>
  </filter-mapping>
  ...
</web-app>

對於全部訪問知足 casTest1/protected-pattern/ 路徑的資源時,都要求到 CAS Server 登陸,若是須要整個 casTest1 均受保護,能夠將 url-pattern 指定爲「/*」。

從清單 10 能夠看到,咱們能夠爲 CASFilter 指定一些參數,而且有些是必須的,表格 1表格 2 中分別是必需和可選的參數:

表格 1. CASFilter 必需的參數
參數名 做用
edu.yale.its.tp.cas.client.filter.loginUrl 指定 CAS 提供登陸頁面的 URL
edu.yale.its.tp.cas.client.filter.validateUrl 指定 CAS 提供 service ticket 或 proxy ticket 驗證服務的 URL
edu.yale.its.tp.cas.client.filter.serverName 指定客戶端的域名和端口,是指客戶端應用所在機器而不是 CAS Server 所在機器,該參數或 serviceUrl 至少有一個必須指定
edu.yale.its.tp.cas.client.filter.serviceUrl 該參數指定事後將覆蓋 serverName 參數,成爲登陸成功事後重定向的目的地址
表格 2. CASFilter 可選參數
參數名 做用
edu.yale.its.tp.cas.client.filter.proxyCallbackUrl 用於當前應用須要做爲其餘服務的代理(proxy)時獲取 Proxy Granting Ticket 的地址
edu.yale.its.tp.cas.client.filter.authorizedProxy 用於容許當前應用從代理處獲取 proxy tickets,該參數接受以空格分隔開的多個 proxy URLs,但實際使用只須要一個成功便可。當指定該參數事後,須要修改 validateUrl 到 proxyValidate,而再也不是 serviceValidate
edu.yale.its.tp.cas.client.filter.renew 若是指定爲 true,那麼受保護的資源每次被訪問時均要求用戶從新進行驗證,而無論以前是否已經經過
edu.yale.its.tp.cas.client.filter.wrapRequest 若是指定爲 true,那麼 CASFilter 將從新包裝 HttpRequest,而且使 getRemoteUser() 方法返回當前登陸用戶的用戶名
edu.yale.its.tp.cas.client.filter.gateway 指定 gateway 屬性

傳遞登陸用戶名

CAS 在登陸成功事後,會給瀏覽器回傳 Cookie,設置新的到的 Service Ticket。但客戶端應用擁有各自的 Session,咱們要怎麼在各個應用中獲取當前登陸用戶的用戶名呢?CAS Client 的 Filter 已經作好了處理,在登陸成功後,就能夠直接從 Session 的屬性中獲取,如清單 11 所示:

清單 11. 在 Java 中經過 Session 獲取登陸用戶名
// 如下二者均可以
session.getAttribute(CASFilter.CAS_FILTER_USER);
session.getAttribute("edu.yale.its.tp.cas.client.filter.user");

在 JSTL 中獲取用戶名的方法如清單 12 所示:

清單 12. 經過 JSTL 獲取登陸用戶名
<c:out value="${sessionScope[CAS:'edu.yale.its.tp.cas.client.filter.user']}"/>

另外,CAS 提供了一個 CASFilterRequestWrapper 類,該類繼承自HttpServletRequestWrapper,主要是重寫了 getRemoteUser() 方法,只要在前面配置 CASFilter 的時候爲其設置「 edu.yale.its.tp.cas.client.filter.wrapRequest 」參數爲 true,就能夠經過 getRemoteUser() 方法來獲取登陸用戶名,具體方法如清單 13 所示:

清單 13. 經過 CASFilterRequestWrapper 獲取登陸用戶名
CASFilterRequestWrapper  reqWrapper=new CASFilterRequestWrapper(request);
out.println("The logon user:" + reqWrapper.getRemoteUser());

效果

在 casTest1 和 casTest2 中,都有一個簡單 Servlet 做爲歡迎頁面 WelcomPage,且該頁面必須登陸事後才能訪問,頁面代碼如清單 14 所示:

清單 14. WelcomePage 頁面代碼
public class WelcomePage extends HttpServlet {
  public void doGet(HttpServletRequest request, HttpServletResponse response)
  throws IOException, ServletException
  {
    response.setContentType("text/html");
    PrintWriter out = response.getWriter();
    out.println("<html>");
    out.println("<head>");
    out.println("<title>Welcome to casTest2 sample System!</title>");
    out.println("</head>");
    out.println("<body>");
    out.println("<h1>Welcome to casTest1 sample System!</h1>");
    CASFilterRequestWrapper  reqWrapper=new CASFilterRequestWrapper(request);
    out.println("<p>The logon user:" + reqWrapper.getRemoteUser() + "</p>");
    HttpSession session=request.getSession();
    out.println("<p>The logon user:" + 
                   session.getAttribute(CASFilter.CAS_FILTER_USER)  + "</p>");
    out.println("<p>The logon user:" + 
         session.getAttribute("edu.yale.its.tp.cas.client.filter.user") + "</p>");
    out.println("</body>");
    out.println("</html>");
    }
}

在上面全部配置結束事後,分別在 A, B, C上啓動 cas, casTest1 和 casTest2,按照下面步驟來訪問 casTest1 和 casTest2:

  1. 打開瀏覽器,訪問 http://domainB:8080/casTest1/WelcomePage ,瀏覽器會彈出安全提示,接受後即轉到 CAS 的登陸頁面,如圖 2 所示:
圖 2. CAS 登陸頁面
CAS 登陸頁面
  1. 登陸成功後,再重定向到 casTest1 的 WelcomePage 頁面,如 所示:
圖 3. 登陸後訪問 casTest1 的效果
登陸後訪問 casTest1 的效果

能夠看到 中地址欄裏的地址多出了一個 ticket 參數,這就是 CAS 分配給當前應用的 ST(Service Ticket)。

  1. 再在同一個瀏覽器的地址欄中輸入 http://domainC:8080/casTest2/WelcomePage ,系統再也不提示用戶登陸,而直接出現如圖 4 所示的頁面,而且顯示在 casTest1 中已經登陸過的用戶。
圖 4. 在 casTest1 中登陸事後訪問 casTest2 的效果
在 casTest1 中登陸事後訪問 casTest2 的效果
  1. 從新打開一個瀏覽器窗口,先輸入 http://domainC:8080/casTest2/WelcomePage ,系統要求登陸,在登陸成功事後,正確顯示 casTest2 的頁面。以後再在地址欄從新輸入 http://domainB:8080/casTest1/WelcomePage ,會直接顯示 casTest1 的頁面而無需再次登陸。

結束語

本文介紹了 CAS 單點登陸解決方案的原理,並結合實例講解了在 Tomcat 中使用 CAS 的配置、部署方法以及效果。CAS 是做爲開源單點登陸解決方案的一個不錯選擇,更多的使用細節能夠參考 CAS 官方網站。

參考資料

條評論

登陸註冊 後發表評論。

注意:評論中不支持 HTML 語法


剩餘 1000 字符


 共有評論 (9) 

講解的版本有些舊了

zeek 於 2015年09月06日發佈


目前最新版本的CAS server 爲 4.0版本,client的版本爲3.X 版本,

IBM的兄弟們還不更新?呵呵

3Y03 於 2014年09月06日發佈


haode

tm123456 於 2014年06月01日發佈


@拾秒10 定時任務同步各系統之間的帳戶信息!

candry 於 2014年01月13日發佈


部署仍是蠻複雜的,還在研究中.

YIYISPACE 於 2014年01月05日發佈

developerWorks: 登陸

標有星(*)號的字段是必填字段。


須要一個 IBM ID?
忘記 IBM ID?


忘記密碼?
更改您的密碼

單擊提交則表示您贊成developerWorks 的條款和條件。 查看條款和條件

 


在您首次登陸 developerWorks 時,會爲您建立一份我的概要。您的我的概要中的信息(您的姓名、國家/地區,以及公司名稱)是公開顯示的,並且會隨着您發佈的任何內容一塊兒顯示,除非您選擇隱藏您的公司名稱。您能夠隨時更新您的 IBM 賬戶。

全部提交的信息確保安全。

選擇您的暱稱



當您初次登陸到 developerWorks 時,將會爲您建立一份概要信息,您須要指定一個暱稱。您的暱稱將和您在 developerWorks 發佈的內容顯示在一塊兒。

暱稱長度在 3 至 31 個字符之間。 您的暱稱在 developerWorks 社區中必須是惟一的,而且出於隱私保護的緣由,不能是您的電子郵件地址。

標有星(*)號的字段是必填字段。

(暱稱長度在 3 至 31 個字符之間)

單擊提交則表示您贊成developerWorks 的條款和條件。 查看條款和條件.

 


全部提交的信息確保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Open source, Security
ArticleID=300459
ArticleTitle=使用 CAS 在 Tomcat 中實現單點登陸
publish-date=04102008
url=http://www.ibm.com/developerworks/cn/opensource/os-cn-cas/