CAS實現的單點登錄系統

SSO的定義是在多個應用系統中,用戶只需要登錄一次就可以訪問所有相互信任的應用系統,而不需要重新登錄。

用一個現實中的例子做比較。頤和園是北京著名的旅遊景點,也是我常去的地方。在頤和園內部有許多獨立的景點,例如“蘇州街”、“佛香閣”和“德和園”,都可以在各個景點門口單獨買票。很多遊客需要遊玩所有德景點,這種買票方式很不方便,需要在每個景點門口排隊買票,錢包拿進拿出的,容易丟失,很不安全。於是絕大多數遊客選擇在大門口買一張通票(也叫套票),就可以玩遍所有的景點而不需要重新再買票。他們只需要在每個景點門口出示一下剛纔買的套票就能夠被允許進入每個獨立的景點。

單點登錄的機制也一樣,如下圖所示,當用戶第一次訪問應用系統1的時候,因爲還沒有登錄,會被引導到認證系統中進行登錄(1);根據用戶提供的登錄信息,認證系統進行身份效驗,如果通過效驗,應該返回給用戶一個認證的憑據--ticket(2);用戶再訪問別的應用的時候(3,5)就會將這個ticket帶上,作爲自己認證的憑據,應用系統接受到請求之後會把ticket送到認證系統進行效驗,檢查ticket的合法性(4,6)。如果通過效驗,用戶就可以在不用再次登錄的情況下訪問應用系統2和應用系統3了。

 

要實現SSO,需要實現以下主要的功能:

所有的應用系統共享一個身份認證系統。

統一的身份認證系統是SSO的前提,認證系統的主要功能是將用戶的登錄信息和用戶信息庫相比較,對用戶進行登錄認證。認證成功後,認證系統應該生成統一的認證標誌(ticket),返還給用戶。另外,認證系統還應該對ticket進行效驗,判斷其有效性。

所有應用系統能夠識別和提取ticket信息

要實現SSO的功能,讓用戶只登錄一次,就必須讓應用系統能夠識別已經登錄過的用戶。應用系統應該能對ticket進行識別和提取,通過與認證系統的通訊,能自動判斷當前用戶是否登錄過,從而完成單點登錄的功能。

以上內容都來自網絡。

 

如何使用CAS實現單點登錄

一、簡介

CAS(Central Authentication Server中央驗證系統)是耶魯大學研發的單點登錄系統。系統爲了安裝考慮默認是需要證書驗證的。

本人使用的環境爲:

apache-tomcat-6.0.30(原來用的是tomcat7,但中途遇到了8443端口無法驗證的問題,懷疑是版本的原因,因此換成了tomcat6。PS:最後找出了原因是域名的問題,後面將會提到)。

JDK6

CAS Server版本:cas-server-3.4.2-release(下載地址:http://downloads.jasig.org/cas/)解壓後,會發現一個modules文件夾,裏面包含了配置CAS server所需要的jar包和war文件。

 

CAS Client版本:cas-client-3.2.1(下載地址:http://downloads.jasig.org/cas-clients/

)解壓後,會發現一個moudules文件夾,裏面包含了配置CAS Client所需要的jar包。

PS:選擇低版本的客戶端可能會出現少jar包的情況。

 

二、安裝證書:

1、用JDK自帶的keytool生成證書

keytool -genkey -alias  smalllove -keyalg RSA -keystore D:/keys/smallkey

 

這一步尤其要注意的是對名字與姓氏的填寫:不要寫localhost或者其他的什麼東西,最好是寫域名,比如我輸入localhost的話,後面8443端口就訪問不到系統了,就這個問題我弄了一天時間才發現。所以,最好是輸入一個域名,然後修改C:\Windows\System32\drivers\etc\hosts文件,在裏面添加映射。

 

2、導出證書:

keytool -export -file d:/keys/small.crt -alias smalllove -keystore d:/keys/smallkey

3、將證書導入到JDK中

進入C:\Program Files\Java\jdk1.6.0_24\jre\lib\security目錄

keytool -import -keystore cacerts -file D:/keys/small.crt -alias smalllove

此處如果某個文件夾包含了空格的話,絕對路徑是不行的。剛開始我根據網上的資料,用絕對路勁來定位,總是出現錯誤,後來仔細看菜發現時我的Program Files目錄裏有空格。所以必須進入到這個目錄下,否則會出現錯誤。

三、HTTPS訪問CAS

將CAS Server解壓出來的war文件部署到eclipse裏面。

將tomcat的server.xml的配置修改一下,

    <Connectorport="8443"protocol="HTTP/1.1"SSLEnabled="true"

               maxThreads="150"scheme="https"secure="true"

               clientAuth="false"sslProtocol="TLS"

               keystoreFile="D:/keys/smallkey"

               keystorePass="123456"/>

注意一定要改對地方,如果是用eclipse配置的tomcat就在對應的服務器的文件裏改。比如我war文件的部署在tomcat v6.0 server at localhost服務器上,就應該改的tomcat v6.0 server at localhost-config裏的server.xml。

好了,此時在瀏覽器裏輸入https://sso.wsria.com:8443/cas就會顯示出如下頁面

可以點擊繼續瀏覽或者將證書安裝到信任區裏。

然後輸入相同的賬戶密碼就OK。如果進入系統後顯示登錄成功頁面,並且在地址欄裏給出了seddionid=…說明CAS Service已經安裝成功。否則的話自己找問題吧^_^。

 

四、客戶端的配置。

完成了服務端,現在我們來解決客戶端。

新建一個兩個web工程myapp1和myapp2,然後修改其web.xml如下:

<?xmlversion="1.0"encoding="UTF-8"?>

<web-appxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://java.sun.com/xml/ns/javaee"xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"id="WebApp_ID"version="2.5">

  <display-name>myapp2</display-name>

 

  <filter> 

        <filter-name>CAS Authentication Filter</filter-name> 

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

       <init-param> 

          

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

           <param-value>https://sso.wsria.com:8443/cas/</param-value> 

      </init-param> 

            <init-param>  

           

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

            <param-value>http://localhost:8082</param-value> 

        </init-param> 

   </filter> 

    <filter-mapping> 

        <filter-name>CAS Authentication Filter</filter-name> 

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

    </filter-mapping> 

   

    <welcome-file-list> 

        <welcome-file>index.jsp</welcome-file> 

    </welcome-file-list> 

</web-app>

我特地將myapp2放在了另外一個tomcat服務器裏面,並改了端口。

引入jar包:cas-client-core-3.2.1.jar、commons-logging-1.1.jar。將這兩個包複製到lib目錄下即可,如果用build path 裏的add external jar來加入這兩個jar包就會提示class not found的錯誤。

此時,登錄myapp1就會跳轉到CAS Server的驗證界面,輸入相同的用戶名密碼,進入myapp1,然後再進入myapp2,此時就不需要驗證了。

 

五、通過數據庫和CAS系統一起實現單點登錄

1、服務器的配置

我安裝的是mysql5.5,這個就不用說了……安裝完成之後,建立一個名爲usr_info的數據庫。然後建表並插入數據:

create table usr(name char(20) not null,password char(20) not null);

insert into usr values("test1" ,"123456");

insert into usr values("test2" ,"223456");

將cas-server-3.4.2裏的modules裏cas-server-support-jdbc-3.4.2.jar和jdbc連接mysql的mysql-connector-java-5.1.18-bin.jar複製到cas項目的WEB-INF的lib目錄下。

修改WEB-INF目錄下的deployerConfigContext.xml文件,將

<bean class="org.jasig.cas.authentication.handler.support.SimpleTestUsernamePasswordAuthenticationHandler" />

屏蔽掉,然後加入以下配置文件:

<beanclass="org.jasig.cas.adaptors.jdbc.SearchModeSearchDatabaseAuthenticationHandler"

              abstract="false"lazy-init="default"autowire="default">

                  <propertyname="tableUsers">

                     <value>usr</value>

                  </property>

                  <propertyname="fieldUser">

                     <value>name</value>

                  </property>

                  <propertyname="fieldPassword">

                     <value>password</value>

                  </property>

              <propertyname="dataSource"ref="dataSource"/>

</bean>

上面這段配置文件主要是添加對用戶名和密碼的校驗工作,常用的有三種校驗方式

l  SimpleTestUsernamePasswordAuthenticationHandler

這個就是默認的簡單的用戶名密碼校驗,只要用戶名和密碼相同就能登錄。

l  QueryDatabaseAuthenticationHandler

這個是用select語句來驗證,具體配置文件可以參考網上寫的。我剛開始時用這種方法,但每次儘管輸入的用戶名和密碼是正確的,還會提示failed to authenticate the user which provided the following credentials:test1,所以我後來改用了指定表和字段來連接。這是一個很容易讓人很糾結的問題。

l  SearchModeSearchDatabaseAuthenticationHandler

這個是通過指定表盒字段來連接數據庫,也就是我的配置文件裏選用的連接方法。

 

最後,在文件的末尾加上以下配置文件:

<beanid="dataSource"class="org.springframework.jdbc.datasource.DriverManagerDataSource">

       <property name="driverClassName"><value>com.mysql.jdbc.Driver</value></property>

       <property name="url"><value>jdbc:mysql:///usr_info</value></property>

       <property name="username"><value>root</value></property>

       <property name="password"><value>123</value></property>

    </bean>

     

    <beanid="MD5PasswordEncoder"class="org.jasig.cas.authentication.handler.DefaultPasswordEncoder"

       <constructor-argindex="0">

           <value>MD5</value>

       </constructor-arg>

    </bean>

上面的這段配置文件實際上就是配置數據源和加密算法,很容易理解。

 

2、客戶端的配置

在myapp1和myapp2的web.xml配置文件里加入如下的filter

    <!--該過濾器負責對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://sso.wsria.com:8443/cas</param-value>

       </init-param>

       <init-param>

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

           <param-value>http://localhost:8081</param-value>

       </init-param>

    </filter>

    <filter-mapping>

       <filter-name>CAS Validation Filter</filter-name>

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

    </filter-mapping>

這樣就完成了客戶端的配置。運行服務器和兩個客戶端,發現輸入admin和admin已經不能登錄系統。只有當輸入用戶名:test1,密碼:123456時才能登錄。

PS:CAS提供的所謂的內存cookie。也就是,如果將所有的瀏覽器關閉,那麼CAS的cookie會自動消失,需要重新登錄。OK 功能完成!

六、客戶端接收參數,以及取得當前登錄的用戶名

    如果我在myapp1系統裏有如下超鏈接:

<a href="http://localhost:8082/myapp2/index.jsp?value=hello">進入myapp2,並攜帶參數value=hello </a>

當某個超鏈接攜帶參數經過CAS驗證後,會不會使得參數丟失呢?答案是不會。並且,其接受參數的方法與沒有集成CAS系統的方法一模一樣。

那麼,在客戶端又應該如何獲得當前登錄用戶的用戶名呢?

<%@ page  import="org.jasig.cas.client.util.AbstractCasFilter"%>

<%@ page  import="org.jasig.cas.client.validation.Assertion"%>

 

<%

    Assertion assertion1=(Assertion)session.getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION);

    String username = assertion1.getPrincipal().getName();

%>

Usernam就是當前登錄用戶的用戶名。

 

到這裏就告一段落了先。

以後將會進一步研究如何在CAS裏實現權限的管理,比如test1用戶只對A系統和B系統有訪問權限,而對C系統沒有訪問權限,那麼test1在登錄過A系統之後,進入B系統就不需要驗證了,進入C系統的話還是需要驗證。可現在是不管進入哪個系統都不需要驗證。那又應該去如何設置呢?

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章