1. 程式人生 > >SSO之CAS單點登入部署

SSO之CAS單點登入部署

專案之前用到單點登入,之前都是網上找了一些資料然後就用上了,中間也遇到了一些問題,這裡總結一下,畢竟以後還是可能再用到這東西的。
這裡摘抄下有關基本概念幫助後面理解CAS的實現

1.基本概念:cookie,session,會話cookie,jssessionid

  • cookie和session機制是為了解決HTTP協議的無狀態而生的;
  • cookie是客戶端儲存使用者資訊的機制;
  • session是伺服器儲存使用者資訊的機制;
  • cookie其實就是在遊覽器中的一個文字,當遊覽器第一次訪問jsp時,jsp response會給遊覽器返回一個cookie,然後遊覽器儲存它;
  • cookie具有不可跨域;
  • cookie和session聯合使用可以解決跨域記錄使用者使用者資訊的問題;
  • 為了使遊覽器記住伺服器的session,遊覽器會生成一個id,這個id就叫做jssessionid;
  • 為了防止一些遊覽器禁用cookie,java EE標準退出了URL的重寫,使url裡面記錄jssessionid;
  • 上述讓遊覽器記住伺服器的session的形式叫做會話cookie,會話cookie在使用者登出或者遊覽器關閉後自動刪除,這樣叫做一次會話;
    這裡如果還對會話cookie和session不清楚,可以看看我轉載的這兩篇文章,講的都是很精闢
    理解了上面的基本概念和標準,對於理解cas的實現和基本流程很有幫助,cas這樣的sso解決方案本來就是構建在cookie和session標準之上的。

2.SSO 和 CAS 介紹

SSO 單點登入,是企業為了解決在相互信任的系統上實現一次登入的解決方案。CAS 是SSO解決方案裡面比較成熟的架構,是耶魯大學發起的一個開源架構。
CAS 具有以下特點:
- 開源的企業級單點登入解決方案。
- CAS Server 為需要獨立部署的 Web 應用。
- CAS Client 支援非常多的客戶端(這裡指單點登入系統中的各個 Web 應用),包括 Java, .Net, PHP, Perl, Apache, uPortal, Ruby 等。
從結構上看,CAS 包含兩個部分: CAS Server 和 CAS Client。CAS Server 需要獨立部署,主要負責對使用者的認證工作;CAS Client 負責處理對客戶端受保護資源的訪問請求,需要登入時,重定向到 CAS Server。

3.CAS基本流程

4.基本配置

1.CAS概述
具體CAS的瞭解可以上官網看,http://www.jasig.org/cas
2.演示環境
這裡我是在自己電腦一臺機上弄得,這裡也可以弄成三臺物理機,只要ip可以訪問到就行了
- Window10 64位
- JDKjdk1.8.0_05
- apache-tomcat-8.0.9
- CAS-server-3.4.11、CAS-client-3.2.1
直接配置下hosts檔案,新增多個域名,用於後面配置時候用,cas的配置都是需要域名的,包括下面的生成證書,ip是不可以,所以這裡虛擬一下

127.0.0.1 server.cas.com
127.0.0.1 client1.cas.com
127.0.0.1 client2.cas.com

3.JDK環境
因為要用到tomcat,因為tomcat也是一個JVM程序,當然JVM也是需要JRE環境才可以執行的。
這裡寫圖片描述
4.安全證書配置
有關keytool工具的詳細運用見:http://www.micmiu.com/lang/java/keytool-start-guide/
4.1 生成證書
這個證書後面要發放到客戶端,認證用的,不然遊覽器會有一個紅色警告,我這裡測試用,所以用的JDK來生成證書,如果嚴格得去CA購買證書,好像是要花錢的。
這裡寫圖片描述
ps:
截圖中需要輸入的姓名和上面hosts檔案中配置的一致;
keypass 和 storepass 兩個密碼要一致,否則下面tomcat 配置https 訪問失敗;
4.2 匯出證書
這裡寫圖片描述
ps:該命令中輸入的密碼和上面輸入的不是同一個密碼;如果是多臺機器演示,需要在每一臺客戶端匯入該證書。
4.3.客戶端匯入證書
這裡寫圖片描述
這裡輸入cacerts證書庫的密碼 changeit,不是我們上面建立證書的密碼,這個是它的預設密碼; 這一步最主要的,一般情況下,沒有把它說明白,其實這一步就是讓cas客戶端伺服器去理解server.cas.com這臺機器所發過來的經過加密的資料(這個涉及到https資料對稱加密互動,不多說了,因為說不明白)
這裡有個地方要主要。有些證書的結尾是以cer結尾的,要將路徑改成d:/sso/cas.cer,不然會報檔案找不到的錯誤。
ps:該命令中輸入的密碼和上面輸入的不是同一個密碼;如果是多臺機器演示,需要在每一臺客戶端匯入該證書。
5.部署CAS-Server相關的Tomcat
5.1. 配置HTTPS
解壓apache-tomcat-8.0.9-windows-x64.zip並重命名後的路徑為 d:\sso\tomcat-cas,在檔案 conf/server.xml檔案找到:

<!-- <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" /> -->

註釋掉,新增這一段

<Connector port="8443" protocol="org.apache.coyote.http11.Http11Protocol"
      SSLEnabled="true"
      maxThreads="150" scheme="https" secure="true"
      clientAuth="false" sslProtocol="TLS"
      keystoreFile="D:/sso/cas.keystore"
      keystorePass="123456" />
  • keystoreFile 就是4.1中建立證書的路徑
  • keystorePass 就是4.1中建立證書的密碼

這裡如果需要省略埠號,將port=”443”,https的預設埠號是443。

5.2. 驗證HTTPS配置
其他按照預設配置不作修改,雙擊%TOMCAT_HOME%\bin\startup.bat 啟動tomcat-cas 驗證https訪問配置:
這裡寫圖片描述
這裡寫圖片描述
如果看到上述介面表示https 訪問配置成功。

5.3 部署CAS-Server
CAS-Server 下載地址:http://www.jasig.org/cas/download
本文以cas-server-3.4.11-release.zip 為例,解壓提取cas-server-3.4.11/modules/cas-server-webapp-3.4.11.war檔案,把改檔案copy到 d:\sso\tomcat-cas\webapps\ 目下,並重命名為:cas.war.
啟動tomcat-cas,發現報了一個錯,這裡把錯誤的圖貼出來
這裡寫圖片描述
感覺好像是JDK版本的問題,於是配置了一下tomcat的JDK為7的,啟動就不報錯了
在瀏覽器位址列輸入:https://server.cas.com:8443/cas/login ,回車
這裡寫圖片描述
CAS-server的預設驗證規則:只要使用者名稱和密碼相同就認證通過(僅僅用於測試,生成環境需要根據實際情況修改),輸入admin/admin 點選登入,就可以看到登入成功的頁面:
這裡寫圖片描述
6.部署CAS-Client相關的Tomcat
6.1Cas-Client 下載
CAS-Client 下載地址:http://downloads.jasig.org/cas-clients/
以cas-client-3.2.1-release.zip 為例,解壓提取cas-client-3.2.1/modules/cas-client-core-3.2.1.jar
藉以tomcat預設自帶的 webapps\examples 作為演示的簡單web專案
6.2 安裝配置 tomcat-client1
解壓apache-tomcat-8.0.9-windows-x64.zip並重命名後的路徑為 d:\sso\tomcat-client1,修改tomcat的啟動埠,在檔案conf/server.xml檔案找到如下內容:

    <Server port="8005" shutdown="SHUTDOWN">
    <!--
    <Connector executor="tomcatThreadPool"
               port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
    -->
    <!-- <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /> -->

修成成這個

<Server port="8006" shutdown="SHUTDOWN">
<Connectorport="18080"protocol="HTTP/1.1"
              connectionTimeout="20000"
              redirectPort="18443"/>
<Connectorport="18009"protocol="AJP/1.3"redirectPort="18443"/>

接下來複制 client的lib包cas-client-core-3.2.1.jar和commons-logging-1.1.jar到 tomcat-client1\webapps\examples\WEB-INF\lib\目錄下, 在tomcat-client1\webapps\examples\WEB-INF\web.xml 檔案中增加如下內容:

<!-- ======================== 單點登入開始 ======================== -->
    <!-- 用於單點退出,該過濾器用於實現單點登出功能,可選配置-->
    <listener>
      <listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
    </listener>

    <!-- 該過濾器用於實現單點登出功能,可選配置。 -->
    <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>CAS Filter</filter-name>
      <filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
      <init-param>
        <param-name>casServerLoginUrl</param-name>
        <param-value>https://server.cas.com:8443/cas/login</param-value>
      </init-param>
      <init-param>
        <param-name>serverName</param-name>
        <param-value>http://client1.cas.com:18080</param-value>
      </init-param>
    </filter>
    <filter-mapping>
      <filter-name>CAS Filter</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://server.cas.com:8443/cas</param-value>
      </init-param>
      <init-param>
        <param-name>serverName</param-name>
        <param-value>http://client1.cas.com:18080</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>

    <!-- ======================== 單點登入結束 ======================== -->

6.3 安裝配置 tomcat-client2
解壓apache-tomcat-8.0.9-windows-x64.zip並重命名後的路徑為 d:\sso\tomcat-client2,修改tomcat的啟動埠,在檔案 conf/server.xml檔案找到如下內容:
對應修改成如下埠

<Server port="8007" shutdown="SHUTDOWN">
<Connector port="28080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="28443" />
<Connector port="28009" protocol="AJP/1.3" redirectPort="28443" />

同6.2中的複製 client的lib包cas-client-core-3.2.1.jar和commons-logging-1.1.jar到 tomcat-client2\webapps\examples\WEB-INF\lib\目錄下, 在tomcat-client2\webapps\examples\WEB-INF\web.xml 檔案中增加如下內容:

<!-- ======================== 單點登入開始 ======================== -->
    <!-- 用於單點退出,該過濾器用於實現單點登出功能,可選配置-->
    <listener>
      <listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
    </listener>

    <!-- 該過濾器用於實現單點登出功能,可選配置。 -->
    <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>CAS Filter</filter-name>
      <filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
      <init-param>
        <param-name>casServerLoginUrl</param-name>
        <param-value>https://server.cas.com:8443/cas/login</param-value>
      </init-param>
      <init-param>
        <param-name>serverName</param-name>
        <param-value>http://client2.cas.com:28080</param-value>
      </init-param>
    </filter>
    <filter-mapping>
      <filter-name>CAS Filter</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://server.cas.com:8443/cas</param-value>
      </init-param>
      <init-param>
        <param-name>serverName</param-name>
        <param-value>http://client2.cas.com:28080</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>

    <!-- ======================== 單點登入結束 ======================== -->

7.測試驗證SSO
啟動配置好的三個tomcat分別為:tomcat-server、tomcat-client1、tomcat-client2
7.1 基本的測試
預期流程: 開啟client1url —-> 跳轉cas server 驗證 —-> 顯示client1的應用 —-> 開啟client2url —-> 顯示app2應用 —-> 登出cas server —-> 開啟client1/client2 url —-> 重新跳轉到cas server 驗證.
開啟瀏覽器位址列中輸入:http://client1.cas.com:18080/examples/servlets/servlet/HelloWorldExample,回車,這裡很遺憾,用微軟新出的Edge遊覽器竟然發現不能跳轉,換了IE11才可以,不知道這個Edge到底特別在那裡
這裡寫圖片描述
跳轉到驗證頁面:
這裡寫圖片描述
這裡可以看到位址列是帶著我們要請求的應用的,登陸進去
這裡寫圖片描述
出現了一個錯誤,先不急,看看位址列是這樣的,http://client1.cas.com:18080/examples/servlets/?ticket=ST-1-DwH9xQLWi1Gh43drwecM-cas,帶了一個ticket,其實這中間還有很多的過程,不單單只是請求了client1。
1.當我們在位址列輸入地址請求client1,client1客戶端先是檢測了session有無令牌憑證資訊(TGT),如果沒有則跳轉的CAS-Server端進行驗證。
2.CAS-Server端檢測到請求沒有帶ST引數,所以跳到Login頁面進行使用者登入驗證。
3.CAS-Server驗證結束,生成TGT令牌和隨機引數ST,並且在使用者的瀏覽器中寫入Cookie-STC,隨後讓使用者的瀏覽器重定向到client1應用中,並將隨機引數ST帶上一起傳參過去,之後client1客戶端將檢測到此ST引數,傳送到server端進行校驗,校驗成功之後,服務端主動銷燬此ST,並繼續返回到client1應用中,client1應用此時將令牌資訊寫入到自己的session中,從而完成使用者的單點登入認證,服務端同樣的也會用一個Map記錄client1加入到單點登入範圍內。
client1端的驗證都是通過我們在web.xml配置的過濾器進行驗證的。
具體CAS的工作原理可以看看這個,這位仁兄寫的非常詳細,讓我收益匪淺。。
接下來繼續解決問題,上網找到一個解決的辦法,http://lyh7609.iteye.com/blog/509064
嘗試了一下
這裡寫圖片描述
這裡寫圖片描述
這裡生成jssecacerts證書是需要訪問cas server的,還有個問題,文章說的是將jssecacerts’的證書放$JAVA_HOME/jre/lib/security目錄,但是我的不行,後來我放到%JAVA_HOME%\jdk1.7.0_07\jre\lib\security下才可以的。
登出
這裡寫圖片描述
上述表示 認證登出成功,此時如果再訪問 : http://client1.cas.com:18080/examples/servlets/servlet/HelloWorldExamplehttp://client1.cas.com:28080/examples/servlets/servlet/HelloWorldExample 需要重新進行認證。
7.2 獲取登入使用者的資訊
找了個jsp頁面做測試D:\sso\tomcat-client1\webapps\examples\jsp\index.jsp,在頁面加上這幾種方法

<%@pageimport="org.jasig.cas.client.authentication.AttributePrincipal" %>

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

String loginName1 = request.getRemoteUser();

%>

request.getRemoteUser(): <%=loginName1%><br/>



<%

AttributePrincipal principal = (AttributePrincipal)request.getUserPrincipal();

String loginName2 = principal.getName();

%>

request.getUserPrincipal().getName():<%=loginName2%><br/>



<%

         Object object =request.getSession().getAttribute("_const_cas_assertion_");

         Assertion assertion =(Assertion)object;

         String loginName3 =assertion.getPrincipal().getName();

%>

request.getSession().getAttribute("_const_cas_assertion_").getPrincipal().getName():<%=loginName3%><br/>

這裡附上整體下載的地址https://github.com/ShawshankLin/sso-cas.git
後續會做一個單點的許可權管理系統。。
單點CAS就介紹到這裡,寫了一個早上,,最近在找實習,順便當複習一下,面試問到不至於尷尬,哈哈,期待找到一份好工作~~