亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

【IBM】使用 CAS 在 Tomcat 中實(shí)現(xiàn)單點(diǎn)登錄

系統(tǒng) 1828 0
張 濤 ?( zzhangt@cn.ibm.com ), 軟件工程師, IBM
王 秉坤 ?( wangbk@cn.ibm.com ), 軟件工程師, IBM?

簡(jiǎn)介: ?單點(diǎn)登錄(Single Sign On , 簡(jiǎn)稱 SSO )是目前比較流行的服務(wù)于企業(yè)業(yè)務(wù)整合的解決方案之一, SSO 使得在多個(gè)應(yīng)用系統(tǒng)中,用戶只需要登錄一次就可以訪問(wèn)所有相互信任的應(yīng)用系統(tǒng)。CAS(Central Authentication Service)是一款不錯(cuò)的針對(duì) Web 應(yīng)用的單點(diǎn)登錄框架,本文介紹了 CAS 的原理、協(xié)議、在 Tomcat 中的配置和使用,對(duì)于采用 CAS 實(shí)現(xiàn)輕量級(jí)單點(diǎn)登錄解決方案的入門讀者具有一定指導(dǎo)作用。

?

CAS 介紹

CAS 是 Yale 大學(xué)發(fā)起的一個(gè)開(kāi)源項(xiàng)目,旨在為 Web 應(yīng)用系統(tǒng)提供一種可靠的單點(diǎn)登錄方法,CAS 在 2004 年 12 月正式成為 JA-SIG 的一個(gè)項(xiàng)目。CAS 具有以下特點(diǎn):

  • 開(kāi)源的企業(yè)級(jí)單點(diǎn)登錄解決方案。
  • CAS Server 為需要獨(dú)立部署的 Web 應(yīng)用。
  • CAS Client 支持非常多的客戶端(這里指單點(diǎn)登錄系統(tǒng)中的各個(gè) Web 應(yīng)用),包括 Java, .Net, PHP, Perl, Apache, uPortal, Ruby 等。

CAS 原理和協(xié)議

從結(jié)構(gòu)上看,CAS 包含兩個(gè)部分: CAS Server 和 CAS Client。CAS Server 需要獨(dú)立部署,主要負(fù)責(zé)對(duì)用戶的認(rèn)證工作;CAS Client 負(fù)責(zé)處理對(duì)客戶端受保護(hù)資源的訪問(wèn)請(qǐng)求,需要登錄時(shí),重定向到 CAS Server。圖1 是 CAS 最基本的協(xié)議過(guò)程:


圖 1. CAS 基礎(chǔ)協(xié)議
CAS 基礎(chǔ)協(xié)議 ?

CAS Client 與受保護(hù)的客戶端應(yīng)用部署在一起,以 Filter 方式保護(hù)受保護(hù)的資源。對(duì)于訪問(wèn)受保護(hù)資源的每個(gè) Web 請(qǐng)求,CAS Client 會(huì)分析該請(qǐng)求的 Http 請(qǐng)求中是否包含 Service Ticket,如果沒(méi)有,則說(shuō)明當(dāng)前用戶尚未登錄,于是將請(qǐng)求重定向到指定好的 CAS Server 登錄地址,并傳遞 Service (也就是要訪問(wèn)的目的資源地址),以便登錄成功過(guò)后轉(zhuǎn)回該地址。用戶在第 3 步中輸入認(rèn)證信息,如果登錄成功,CAS Server 隨機(jī)產(chǎn)生一個(gè)相當(dāng)長(zhǎng)度、唯一、不可偽造的 Service Ticket,并緩存以待將來(lái)驗(yàn)證,之后系統(tǒng)自動(dòng)重定向到 Service 所在地址,并為客戶端瀏覽器設(shè)置一個(gè) Ticket Granted Cookie(TGC),CAS Client 在拿到 Service 和新產(chǎn)生的 Ticket 過(guò)后,在第 5,6 步中與 CAS Server 進(jìn)行身份合適,以確保 Service Ticket 的合法性。

在該協(xié)議中,所有與 CAS 的交互均采用 SSL 協(xié)議,確保,ST 和 TGC 的安全性。協(xié)議工作過(guò)程中會(huì)有 2 次重定向的過(guò)程,但是 CAS Client 與 CAS Server 之間進(jìn)行 Ticket 驗(yàn)證的過(guò)程對(duì)于用戶是透明的。

另外,CAS 協(xié)議中還提供了 Proxy (代理)模式,以適應(yīng)更加高級(jí)、復(fù)雜的應(yīng)用場(chǎng)景,具體介紹可以參考 CAS 官方網(wǎng)站上的相關(guān)文檔。

準(zhǔn)備工作

本文中的例子以 tomcat5.5 為例進(jìn)行講解,下載地址:

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

到 CAS 官方網(wǎng)站下載 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 實(shí)現(xiàn)的服務(wù),該服務(wù)以一個(gè) Java Web Application 單獨(dú)部署在與 servlet2.3 兼容的 Web 服務(wù)器上,另外,由于 Client 與 CAS Server 之間的交互采用 Https 協(xié)議,因此部署 CAS Server 的服務(wù)器還需要支持 SSL 協(xié)議。當(dāng) SSL 配置成功過(guò)后,像普通 Web 應(yīng)用一樣將 CAS Server 部署在服務(wù)器上就能正常運(yùn)行了,不過(guò),在真正使用之前,還需要擴(kuò)展驗(yàn)證用戶的接口。

在 Tomcat 上部署一個(gè)完整的 CAS Server 主要按照以下幾個(gè)步驟:

配置 Tomcat 使用 Https 協(xié)議

如果希望 Tomcat 支持 Https,主要的工作是配置 SSL 協(xié)議,其配置過(guò)程和配置方法可以參考 Tomcat 的相關(guān)文檔。不過(guò)在生成證書(shū)的過(guò)程中,會(huì)有需要用到主機(jī)名的地方,CAS 建議不要使用 IP 地址,而要使用機(jī)器名或域名。

部署 CAS Server

CAS Server 是一個(gè) Web 應(yīng)用包,將前面下載的 cas-server-3.1.1-release.zip 解開(kāi),把其中的 cas-server-webapp-3.1.1.war 拷貝到 tomcat的 webapps 目錄,并更名為 cas.war。由于前面已配置好 tomcat 的 https 協(xié)議,可以重新啟動(dòng) tomcat,然后訪問(wèn):https://localhost:8443/cas ,如果能出現(xiàn)正常的 CAS 登錄頁(yè)面,則說(shuō)明 CAS Server 已經(jīng)部署成功。

雖然 CAS Server 已經(jīng)部署成功,但這只是一個(gè)缺省的實(shí)現(xiàn),在實(shí)際使用的時(shí)候,還需要根據(jù)實(shí)際概況做擴(kuò)展和定制,最主要的是擴(kuò)展認(rèn)證 (Authentication) 接口和 CAS Server 的界面。

擴(kuò)展認(rèn)證接口

CAS Server 負(fù)責(zé)完成對(duì)用戶的認(rèn)證工作,它會(huì)處理登錄時(shí)的用戶憑證 (Credentials) 信息,用戶名/密碼對(duì)是最常見(jiàn)的憑證信息。CAS Server 可能需要到數(shù)據(jù)庫(kù)檢索一條用戶帳號(hào)信息,也可能在 XML 文件中檢索用戶名/密碼,還可能通過(guò) LDAP Server 獲取等,在這種情況下,CAS 提供了一種靈活但統(tǒng)一的接口和實(shí)現(xiàn)分離的方式,實(shí)際使用中 CAS 采用哪種方式認(rèn)證是與 CAS 的基本協(xié)議分離開(kāi)的,用戶可以根據(jù)認(rèn)證的接口去定制和擴(kuò)展。

擴(kuò)展 AuthenticationHandler

CAS 提供擴(kuò)展認(rèn)證的核心是 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 個(gè)需要實(shí)現(xiàn)的方法,supports ()方法用于檢查所給的包含認(rèn)證信息的Credentials 是否受當(dāng)前 AuthenticationHandler 支持;而 authenticate() 方法則擔(dān)當(dāng)驗(yàn)證認(rèn)證信息的任務(wù),這也是需要擴(kuò)展的主要方法,根據(jù)情況與存儲(chǔ)合法認(rèn)證信息的介質(zhì)進(jìn)行交互,返回 boolean 類型的值,true 表示驗(yàn)證通過(guò),false 表示驗(yàn)證失敗。

CAS3中還提供了對(duì)AuthenticationHandler 接口的一些抽象實(shí)現(xiàn),比如,可能需要在執(zhí)行authenticate() 方法前后執(zhí)行某些其他操作,那么可以讓自己的認(rèn)證類擴(kuò)展自清單 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() 方法,而實(shí)際的認(rèn)證工作交由 doAuthentication() 方法來(lái)執(zhí)行。因此,如果需要在認(rèn)證前后執(zhí)行一些額外的操作,可以分別擴(kuò)展 preAuthenticate()和 ppstAuthenticate() 方法,而 doAuthentication() 取代 authenticate() 成為了子類必須要實(shí)現(xiàn)的方法。

由于實(shí)際運(yùn)用中,最常用的是用戶名和密碼方式的認(rèn)證,CAS3 提供了針對(duì)該方式的實(shí)現(xiàn),如清單 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;

    }

...

}


                

基于用戶名密碼的認(rèn)證方式可直接擴(kuò)展自 AbstractUsernamePasswordAuthenticationHandler,驗(yàn)證用戶名密碼的具體操作通過(guò)實(shí)現(xiàn) authenticateUsernamePasswordInternal() 方法達(dá)到,另外,通常情況下密碼會(huì)是加密過(guò)的,setPasswordEncoder() 方法就是用于指定適當(dāng)?shù)募用芷鳌?

從以上清單中可以看到,doAuthentication() 方法的參數(shù)是 Credentials 類型,這是包含用戶認(rèn)證信息的一個(gè)接口,對(duì)于用戶名密碼類型的認(rèn)證信息,可以直接使用 UsernamePasswordCredentials,如果需要擴(kuò)展其他類型的認(rèn)證信息,需要實(shí)現(xiàn)Credentials接口,并且實(shí)現(xiàn)相應(yīng)的 CredentialsToPrincipalResolver 接口,其具體方法可以借鑒 UsernamePasswordCredentials 和 UsernamePasswordCredentialsToPrincipalResolver。

JDBC 認(rèn)證方法

用戶的認(rèn)證信息通常保存在數(shù)據(jù)庫(kù)中,因此本文就選用這種情況來(lái)介紹。將前面下載的 cas-server-3.1.1-release.zip 包解開(kāi)后,在 modules 目錄下可以找到包 cas-server-support-jdbc-3.1.1.jar,其提供了通過(guò) JDBC 連接數(shù)據(jù)庫(kù)進(jìn)行驗(yàn)證的缺省實(shí)現(xiàn),基于該包的支持,我們只需要做一些配置工作即可實(shí)現(xiàn) JDBC 認(rèn)證。

JDBC 認(rèn)證方法支持多種數(shù)據(jù)庫(kù),DB2, Oracle, MySql, Microsoft SQL Server 等均可,這里以 DB2 作為例子介紹。并且假設(shè)DB2數(shù)據(jù)庫(kù)名: CASTest,數(shù)據(jù)庫(kù)登錄用戶名: db2user,數(shù)據(jù)庫(kù)登錄密碼: db2password,用戶信息表為: userTable,該表包含用戶名和密碼的兩個(gè)數(shù)據(jù)項(xiàng)分別為 userName 和 password。

1.? 配置 ? DataStore

打開(kāi)文件 %CATALINA_HOME%/webapps/cas/WEB-INF/deployerConfigContext.xml,添加一個(gè)新的 bean 標(biāo)簽,對(duì)于 DB2,內(nèi)容如清單 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 的標(biāo)識(shí),在后面配置 AuthenticationHandler 會(huì)被引用,另外,需要提供 DataStore 所必需的數(shù)據(jù)庫(kù)驅(qū)動(dòng)程序、連接地址、數(shù)據(jù)庫(kù)登錄用戶名以及登錄密碼。

2. 配置 AuthenticationHandler

在 cas-server-support-jdbc-3.1.1.jar 包中,提供了 3 個(gè)基于 JDBC 的 AuthenticationHandler,分別為 BindModeSearchDatabaseAuthenticationHandler, QueryDatabaseAuthenticationHandler, SearchModeSearchDatabaseAuthenticationHandler。其中 BindModeSearchDatabaseAuthenticationHandler 是用所給的用戶名和密碼去建立數(shù)據(jù)庫(kù)連接,根據(jù)連接建立是否成功來(lái)判斷驗(yàn)證成功與否;QueryDatabaseAuthenticationHandler 通過(guò)配置一個(gè) SQL 語(yǔ)句查出密碼,與所給密碼匹配;SearchModeSearchDatabaseAuthenticationHandler 通過(guò)配置存放用戶驗(yàn)證信息的表、用戶名字段和密碼字段,構(gòu)造查詢語(yǔ)句來(lái)驗(yàn)證。

使用哪個(gè) AuthenticationHandler,需要在 deployerConfigContext.xml 中設(shè)置,默認(rèn)情況下,CAS 使用一個(gè)簡(jiǎn)單的 username=password 的 AuthenticationHandler,在文件中可以找到如下一行:<bean class="org.jasig.cas.authentication.handler.support.SimpleTestUsernamePassword
AuthenticationHandler" />,我們可以將其注釋掉,換成我們希望的一個(gè) 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>




                

另外,由于存放在數(shù)據(jù)庫(kù)中的密碼通常是加密過(guò)的,所以 AuthenticationHandler 在匹配時(shí)需要知道使用的加密方法,在 deployerConfigContext.xml 文件中我們可以為具體的 AuthenticationHandler 類配置一個(gè) property,指定加密器類,比如對(duì)于 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 是對(duì)清單 8 中設(shè)置的實(shí)際加密器類的引用:


清單 8. 指定具體加密器類
                                  

<bean id="passwordEncoder" 

            class="org.jasig.cas.authentication.handler.MyPasswordEncoder"/>


                

這里 MyPasswordEncoder 是根據(jù)實(shí)際情況自己定義的加密器,實(shí)現(xiàn) PasswordEncoder 接口及其 encode() 方法。

3. 部署依賴包

在以上配置完成以后,需要拷貝幾個(gè)依賴的包到 cas 應(yīng)用下,包括:

  • 將 cas-server-support-jdbc-3.1.1.jar 拷貝到 %CATALINA_HOME%/webapps/cas/ WEB-INF/lib 目錄。
  • 數(shù)據(jù)庫(kù)驅(qū)動(dòng),由于這里使用 DB2,將 %DB2_HOME%/java 目錄下的 db2java.zip (更名為 db2java.jar), db2jcc.jar, db2jcc_license_cu.jar 拷貝到 %CATALINA_HOME%/webapps/cas/WEB-INF/lib 目錄。對(duì)于其他數(shù)據(jù)庫(kù),同樣將相應(yīng)數(shù)據(jù)庫(kù)驅(qū)動(dòng)程序拷貝到該目錄。
  • DataStore 依賴于 commons-collections-3.2.jar, commons-dbcp-1.2.1.jar, commons-pool-1.3.jar,需要到 apache 網(wǎng)站的 Commons 項(xiàng)目下載以上 3 個(gè)包放進(jìn) %CATALINA_HOME%/webapps/cas/WEB-INF/lib 目錄。

擴(kuò)展 CAS Server 界面

CAS 提供了 2 套默認(rèn)的頁(yè)面,分別為“ default ”和“ simple ”,分別在目錄“ cas/WEB-INF/view/jsp/default ”和“ cas/WEB-INF/view/jsp/simple ”下。其中 default 是一個(gè)稍微復(fù)雜一些的頁(yè)面,使用 CSS,而 simple 則是能讓 CAS 正常工作的最簡(jiǎn)化的頁(yè)面。

在部署 CAS 之前,我們可能需要定制一套新的 CAS Server 頁(yè)面,添加一些個(gè)性化的內(nèi)容。最簡(jiǎn)單的方法就是拷貝一份 default 或 simple 文件到“ cas/WEB-INF/view/jsp ”目錄下,比如命名為 newUI,接下來(lái)是實(shí)現(xiàn)和修改必要的頁(yè)面,有 4 個(gè)頁(yè)面是必須的:

  • casConfirmView.jsp: 當(dāng)用戶選擇了“ warn ”時(shí)會(huì)看到的確認(rèn)界面
  • casGenericSuccess.jsp: 在用戶成功通過(guò)認(rèn)證而沒(méi)有目的Service時(shí)會(huì)看到的界面
  • casLoginView.jsp: 當(dāng)需要用戶提供認(rèn)證信息時(shí)會(huì)出現(xiàn)的界面
  • casLogoutView.jsp: 當(dāng)用戶結(jié)束 CAS 單點(diǎn)登錄系統(tǒng)會(huì)話時(shí)出現(xiàn)的界面

CAS 的頁(yè)面采用 Spring 框架編寫(xiě),對(duì)于不熟悉 Spring 的使用者,在修改之前需要熟悉該框架。

頁(yè)面定制完過(guò)后,還需要做一些配置從而讓 CAS 找到新的頁(yè)面,拷貝“ cas/WEB-INF/classes/default_views.properties ”,重命名為“ cas/WEB-INF/classes/ newUI_views.properties ”,并修改其中所有的值到相應(yīng)新頁(yè)面。最后是更新“ cas/WEB-INF/cas-servlet.xml ”文件中的 viewResolver,將其修改為如清單 9 中的內(nèi)容。


清單 9. 指定 CAS 頁(yè)面
                                  

<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>


                

?

部署客戶端應(yīng)用

單點(diǎn)登錄的目的是為了讓多個(gè)相關(guān)聯(lián)的應(yīng)用使用相同的登錄過(guò)程,本文在講解過(guò)程中構(gòu)造 2個(gè)簡(jiǎn)單的應(yīng)用,分別以 casTest1 和 casTest2 來(lái)作為示例,它們均只有一個(gè)頁(yè)面,顯示歡迎信息和當(dāng)前登錄用戶名。這 2 個(gè)應(yīng)用使用同一套登錄信息,并且只有登錄過(guò)的用戶才能訪問(wèn),通過(guò)本文的配置,實(shí)現(xiàn)單點(diǎn)登錄,即只需登錄一次就可以訪問(wèn)這兩個(gè)應(yīng)用。

與 CAS Server 建立信任關(guān)系

假設(shè) CAS Server 單獨(dú)部署在一臺(tái)機(jī)器 A,而客戶端應(yīng)用部署在機(jī)器 B 上,由于客戶端應(yīng)用與 CAS Server 的通信采用 SSL,因此,需要在 A 與 B 的 JRE 之間建立信任關(guān)系。

首先與 A 機(jī)器一樣,要生成 B 機(jī)器上的證書(shū),配置 Tomcat 的 SSL 協(xié)議。其次,下載 http://blogs.sun.com/andreas/entry/no_more_unable_to_find ?的 InstallCert.java,運(yùn)行“ java InstallCert compA:8443 ”命令,并且在接下來(lái)出現(xiàn)的詢問(wèn)中輸入 1。這樣,就將 A 添加到了 B 的 trust store 中。如果多個(gè)客戶端應(yīng)用分別部署在不同機(jī)器上,那么每個(gè)機(jī)器都需要與 CAS Server 所在機(jī)器建立信任關(guān)系。

配置 CAS Filter

準(zhǔn)備好應(yīng)用 casTest1 和 casTest2 過(guò)后,分別部署在 B 和 C 機(jī)器上,由于 casTest1 和casTest2,B 和 C 完全等同,我們以 casTest1 在 B 機(jī)器上的配置做介紹,假設(shè) 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>




                

對(duì)于所有訪問(wèn)滿足 casTest1/protected-pattern/ 路徑的資源時(shí),都要求到 CAS Server 登錄,如果需要整個(gè) casTest1 均受保護(hù),可以將 url-pattern 指定為“/*”。

從清單 10 可以看到,我們可以為 CASFilter 指定一些參數(shù),并且有些是必須的, 表格 1 ?和 表格 2 ?中分別是必需和可選的參數(shù):


表格 1. CASFilter 必需的參數(shù)
參數(shù)名 作用
edu.yale.its.tp.cas.client.filter.loginUrl 指定 CAS 提供登錄頁(yè)面的 URL
edu.yale.its.tp.cas.client.filter.validateUrl 指定 CAS 提供 service ticket 或 proxy ticket 驗(yàn)證服務(wù)的 URL
edu.yale.its.tp.cas.client.filter.serverName 指定客戶端的域名和端口,是指客戶端應(yīng)用所在機(jī)器而不是 CAS Server 所在機(jī)器,該參數(shù)或 serviceUrl 至少有一個(gè)必須指定
edu.yale.its.tp.cas.client.filter.serviceUrl 該參數(shù)指定過(guò)后將覆蓋 serverName 參數(shù),成為登錄成功過(guò)后重定向的目的地址


表格 2. CASFilter 可選參數(shù)
參數(shù)名 作用
edu.yale.its.tp.cas.client.filter.proxyCallbackUrl 用于當(dāng)前應(yīng)用需要作為其他服務(wù)的代理(proxy)時(shí)獲取 Proxy Granting Ticket 的地址
edu.yale.its.tp.cas.client.filter.authorizedProxy 用于允許當(dāng)前應(yīng)用從代理處獲取 proxy tickets,該參數(shù)接受以空格分隔開(kāi)的多個(gè) proxy URLs,但實(shí)際使用只需要一個(gè)成功即可。當(dāng)指定該參數(shù)過(guò)后,需要修改 validateUrl 到 proxyValidate,而不再是 serviceValidate
edu.yale.its.tp.cas.client.filter.renew 如果指定為 true,那么受保護(hù)的資源每次被訪問(wèn)時(shí)均要求用戶重新進(jìn)行驗(yàn)證,而不管之前是否已經(jīng)通過(guò)
edu.yale.its.tp.cas.client.filter.wrapRequest 如果指定為 true,那么 CASFilter 將重新包裝 HttpRequest,并且使 getRemoteUser() 方法返回當(dāng)前登錄用戶的用戶名
edu.yale.its.tp.cas.client.filter.gateway 指定 gateway 屬性

傳遞登錄用戶名

CAS 在登錄成功過(guò)后,會(huì)給瀏覽器回傳 Cookie,設(shè)置新的到的 Service Ticket。但客戶端應(yīng)用擁有各自的 Session,我們要怎么在各個(gè)應(yīng)用中獲取當(dāng)前登錄用戶的用戶名呢?CAS Client 的 Filter 已經(jīng)做好了處理,在登錄成功后,就可以直接從 Session 的屬性中獲取,如清單 11 所示:


清單 11. 在 Java 中通過(guò) Session 獲取登錄用戶名
                                  

// 以下兩者都可以

session.getAttribute(CASFilter.CAS_FILTER_USER);

session.getAttribute("edu.yale.its.tp.cas.client.filter.user");




                

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


清單 12. 通過(guò) JSTL 獲取登錄用戶名
                                  

<c:out value="${sessionScope[CAS:'edu.yale.its.tp.cas.client.filter.user']}"/>


                

另外,CAS 提供了一個(gè) CASFilterRequestWrapper 類,該類繼承自HttpServletRequestWrapper,主要是重寫(xiě)了 getRemoteUser() 方法,只要在前面配置 CASFilter 的時(shí)候?yàn)槠湓O(shè)置“ edu.yale.its.tp.cas.client.filter.wrapRequest ”參數(shù)為 true,就可以通過(guò) getRemoteUser() 方法來(lái)獲取登錄用戶名,具體方法如清單 13 所示:


清單 13. 通過(guò) CASFilterRequestWrapper 獲取登錄用戶名
                                  

CASFilterRequestWrapper  reqWrapper=new CASFilterRequestWrapper(request);

out.println("The logon user:" + reqWrapper.getRemoteUser());


                

?

效果

在 casTest1 和 casTest2 中,都有一個(gè)簡(jiǎn)單 Servlet 作為歡迎頁(yè)面 WelcomPage,且該頁(yè)面必須登錄過(guò)后才能訪問(wèn),頁(yè)面代碼如清單 14 所示:


清單 14. WelcomePage 頁(yè)面代碼
                                  

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>");

    }

}




                

在上面所有配置結(jié)束過(guò)后,分別在 A, B, C上啟動(dòng) cas, casTest1 和 casTest2,按照下面步驟來(lái)訪問(wèn) casTest1 和 casTest2:

  1. 打開(kāi)瀏覽器,訪問(wèn)? http://domainB:8080/casTest1/WelcomePage ?,瀏覽器會(huì)彈出安全提示,接受后即轉(zhuǎn)到 CAS 的登錄頁(yè)面,如圖 2 所示:

圖 2. CAS 登錄頁(yè)面
CAS 登錄頁(yè)面 ?
  1. 登錄成功后,再重定向到 casTest1 的 WelcomePage 頁(yè)面,如 圖? 所示:

圖 3. 登錄后訪問(wèn) casTest1 的效果
登錄后訪問(wèn) casTest1 的效果 ?

可以看到 圖? 中地址欄里的地址多出了一個(gè) ticket 參數(shù),這就是 CAS 分配給當(dāng)前應(yīng)用的 ST(Service Ticket)。

  1. 再在同一個(gè)瀏覽器的地址欄中輸入? http://domainC:8080/casTest2/WelcomePage ?,系統(tǒng)不再提示用戶登錄,而直接出現(xiàn)如圖 4 所示的頁(yè)面,并且顯示在 casTest1 中已經(jīng)登錄過(guò)的用戶。

圖 4. 在 casTest1 中登錄過(guò)后訪問(wèn) casTest2 的效果
在 casTest1 中登錄過(guò)后訪問(wèn) casTest2 的效果 ?
  1. 重新打開(kāi)一個(gè)瀏覽器窗口,先輸入? http://domainC:8080/casTest2/WelcomePage ?,系統(tǒng)要求登錄,在登錄成功過(guò)后,正確顯示 casTest2 的頁(yè)面。之后再在地址欄重新輸入? http://domainB:8080/casTest1/WelcomePage ?,會(huì)直接顯示 casTest1 的頁(yè)面而無(wú)需再次登錄。
?

結(jié)束語(yǔ)

本文介紹了 CAS 單點(diǎn)登錄解決方案的原理,并結(jié)合實(shí)例講解了在 Tomcat 中使用 CAS 的配置、部署方法以及效果。CAS 是作為開(kāi)源單點(diǎn)登錄解決方案的一個(gè)不錯(cuò)選擇,更多的使用細(xì)節(jié)可以參考 CAS 官方網(wǎng)站。


參考資料

作者簡(jiǎn)介

張濤,IBM 中國(guó)軟件開(kāi)發(fā)實(shí)驗(yàn)室工程師,目前主要致力于基于 Rational 平臺(tái)解決方案的開(kāi)發(fā)。

王秉坤,IBM 中國(guó)軟件開(kāi)發(fā)實(shí)驗(yàn)室工程師,目前主要致力于基于 Rational 平臺(tái)解決方案的開(kāi)發(fā)。

【IBM】使用 CAS 在 Tomcat 中實(shí)現(xiàn)單點(diǎn)登錄


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長(zhǎng)會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 亚洲不卡在线 | 亚洲综合爱爱久久网 | 久久久久国产 | 四虎国产精品成人永久免费影视 | 久久精品国产久精国产80cm | 日产国产欧美视频一区精品 | 国产精品福利影院 | 精品视频 九九九 | 天天摸夜夜 | 99麻豆视频| 欧美色爱综合 | 黄色成人一级片 | 久久精品99久久香蕉国产色戒 | 国产一级理论免费版 | 久久66久这里精品99 | 精品国产午夜久久久久九九 | 劲爆激情欧美毛片 | 久草婷婷在线 | 国产亚洲欧美在线观看的 | 伊人久久在线视频 | 国产精品亚洲精品久久成人 | 日本在线不卡视频 | 国产免费一级高清淫日本片 | 色图综合网| 国产福利视频 | 欧美伊人久久久久久久久影院 | 福利视频在线观看午夜 | 天天综合射 | 手机看黄av免费网址 | 国产福利免费在线观看 | 国产福利在线永久视频 | 九九热视频免费观看 | 欧美精品国产第一区二区 | 激情综合五月亚洲婷婷 | 国产免费一级高清淫日本片 | 日本不卡一区二区三区视频 | 青青青国产精品手机在线观看 | 国产精品入口麻豆 | 人人干人人舔 | 97在线观看完整免费 | 四虎影视久久 |