SSO英文全稱Single Sign On,單點登陸。SSO是在多個應用系統中,用戶只須要登陸一次就能夠訪問全部相互信任的應用系統。它包括能夠將此次主要的登陸映射到其餘應用中用於同一個用戶的登陸的機制。它是目前比較流行的企業業務整合的解決方案之一。html
SSO的實現機制是:java
當用戶第一次訪問應用系統1的時候,由於尚未登陸,會被引導到認證系統中進行登陸;根據用戶提供的登陸信息,認證系統進行身份校驗,若是經過校驗,應該返回給用戶一個認證的憑據--ticket;用戶再訪問別的應用的時候就會將這個ticket帶上,做爲本身認證的憑據,應用系統接受到請求以後會把ticket送到認證系統進行校驗,檢查ticket的合法性。若是經過校驗,用戶就能夠在不用再次登陸的狀況下訪問應用系統2和應用系統3了。
要實現SSO,須要如下主要的功能:mysql
(1)系統共享
統一的認證系統是SSO的前提之一。認證系統的主要功能是將用戶的登陸信息和用戶信息庫相比較,對用戶進行登陸認證;認證成功後,認證系統應該生成統一的認證標誌(ticket),返還給用戶。另外,認證系統還應該對ticket進行校驗,判斷其有效性。
(2)信息識別
要實現SSO的功能,讓用戶只登陸一次,就必須讓應用系統可以識別已經登陸過的用戶。應用系統應該能對ticket進行識別和提取,經過與認證系統的通信,能自動判斷當前用戶是否登陸過,從而完成單點登陸的功能。web
單點登陸在web項目中有着普遍運用。好比,用戶在訪問頁面1的時候進行了登陸,可是客戶端的每一個請求都是單獨的鏈接,當客戶再次訪問頁面2的時候,如何才能告訴Web服務器,客戶剛纔已經登陸過了呢?瀏覽器和服務器之間有約定:經過使用cookie技術來維護應用的狀態。Cookie是能夠被Web服務器設置的字符串,而且能夠保存在瀏覽器中。當瀏覽器訪問了頁面1時,web服務器設置了一個cookie,並將這個cookie和頁面1一塊兒返回給瀏覽器,瀏覽器接到cookie以後,就會保存起來,在它訪問頁面2的時候會把這個cookie也帶上,Web服務器接到請求時也能讀出cookie的值,根據cookie值的內容就能夠判斷和恢復一些用戶的信息狀態。Web-SSO徹底能夠利用Cookie技術來完成用戶登陸信息的保存,將瀏覽器中的Cookie和上文中的Ticket結合起來,完成SSO的功能。spring
爲了完成一個簡單的SSO的功能,須要兩個部分的合做:
(1)統一的身份認證服務。
(2)修改Web應用,使得每一個應用都經過這個統一的認證服務來進行身份校驗。sql
目前,實現SSO的技術主要有:
(1)基於cookies實現。
(2) Broker-based(基於經紀人)。這種技術的特色是:有一個集中的認證和用戶賬號管理的服務器,爲認證提供一個公共和獨立的"第三方"。Kerberos是由麻省理工大學發明的安全認證服務,當前版本V5,已經被UNIX和Windows做爲默認的安全認證服務集成進操做系統。
(3) Agent-based(基於代理人)。在這種解決方案中,有一個自動地爲不一樣的應用程序認證用戶身份的代理程序。這個代理程序須要設計有不一樣的功能。好比,它可使用口令表或加密密鑰來自動地將認證的負擔從用戶移開。代理人被放在服務器上面,在服務器的認證系統和客戶端認證方法之間充當一個"翻譯"。例如SSH等。數據庫
SSH,全稱Secure Shell,安全外殼協議,是創建在應用層基礎上的安全協議。SSH 是目前較可靠,專爲遠程登陸會話和其餘網絡服務提供安全性的協議。利用 SSH 協議能夠有效防止遠程管理過程當中的信息泄露問題。
(4) Token-based。例如SecurID,WebID,如今被普遍使用的口令認證,好比FTP,郵件服務器的登陸認證,這是一種簡單易用的方式,實現一個口令在多種應用當中使用。
(5) 基於網關Agent and Broker-based。
(6) 基於安全斷言標記語言(SAML)實現。SAML(Security Assertion Markup Language,安全斷言標記語言)的出現大大簡化了SSO,並被OASIS批准爲SSO的執行標準。開源組織OpenSAML 實現了 SAML 規範。
(7)CAS由耶魯大學開發的單點登陸系統(SSO,single sign-on),應用普遍,具備獨立於平臺,易於理解,支持代理的功能。apache
接下來,咱們先實現CAS的初步搭建,而後實現多個應用系統基於CAS進行單點登陸。瀏覽器
一.初步搭建CAStomcat
1.把CAS的server發佈到一臺獨立的tomcat上。
從網上下載cas-server-4.0.0-release.zip,解壓後,拷貝出cas-server-4.0.0\modules\cas-server-webapp-4.0.0.war,爲了簡化起見,將cas-server-webapp-4.0.0.war改名爲cas-server.war,而後將這個war文件拷貝到到一個tomcat的webapps文件夾下。tomcat啓動時,會自動解壓war文件。
2.配置https。
因爲CAS單點登陸爲了保障安全,所以必須基於https來搭建。
(1)鑑於https的要求,咱們以win7系統爲例,須要在C:\Windows\System32\drivers\etc\hosts中配置幾個域名,以下:
127.0.0.1 dddr.money.com 127.0.0.1 dddr.store.com 127.0.0.1 dddr.cas.com
(2)生成ssl須要的證書。
①生成keystore: keytool -genkey -alias dddritszt -keyalg RSA -keysize 1024 -keypass 123456 -validity 365 -keystore C:\Users\Administrator\Desktop\cas\ssl\dddritszt.keystore -storepass 123456 ②轉換keystore: keytool -export -alias dddritszt -keystore C:\Users\Administrator\Desktop\cas\ssl\dddritszt.keystore -file C:\Users\Administrator\Desktop\cas\ssl\dddritszt.crt -storepass 123456 ③信任證書【注意:JDK的java_home的路徑中有中文或者空格都不行,好比我設置的java_home值爲:E:\Java\jdk1.8.0_131】: keytool -import -keystore %JAVA_HOME%\jre\lib\security\cacerts -file C:\Users\Administrator\Desktop\cas\ssl\dddritszt.crt -alias dddritszt 這一步按回車鍵後,會提示輸入密碼,請輸入:changeit 因爲要將證書導入jdk,所以輸入的是jdk默認的祕鑰。
(3)給tomcat配置https。在tomcat的conf/server.xml文件中添加下述配置:
<Connector port="8443" protocol="org.apache.coyote.http11.Http11Protocol" SSLEnabled="true" maxThreads="150" scheme="https" secure="true" keystoreFile="C:\Users\Administrator\Desktop\cas\ssl\dddritszt.keystore" keystorePass="123456" clientAuth="false" sslProtocol="TLS" URIEncoding="UTF-8"/>
到此就搭建好了CAS,接着開啓tomcat服務器,在瀏覽器的地址欄中輸入 https://dddr.cas.com:8443/cas-server/login,顯示頁面以下:
我在網上看到,有人說爲了找出用戶名和密碼應該填什麼,折騰了4個小時,在這裏提醒你們,CAS默認,用戶名是:casuser,密碼是:Mellon。登陸成功後,頁面顯示以下:
咱們還能夠經過CAS登出,在瀏覽器地址欄中修改url路徑爲 https://dddr.cas.com:8443/cas-server/logout,顯示頁面以下:
在演示完畢搭建CAS服務後,咱們接下來進行多個應用系統在CAS上實現單點登陸。
二.多個應用系統在CAS上實現單點登陸。
1.再部署兩個tomcat,http訪問端口分別爲17070和18080,這兩個tomcat上將發佈咱們的測試案例。
(1)在idea中建立一個webApp項目,名稱爲「DDDR_CAS_Money」,在該項目的web/WEB-INF下新建一個lib文件夾,拷貝CAS客戶端的一個jar包(此處爲cas-client-core-3.3.3.jar)到該lib文件夾下,並將這個jar包配置爲項目依賴。
注意,該項目的SDK(Software Development Kit,軟件開發工具包),此處主要是指Java,要和添加證書信賴的Java路徑一致。
另外,本項目所在的tomcat的conf/server.xml文件中,端口號不要和CAS服務器上的端口號衝突。我是這樣配置的,親測後,能夠正常訪問:
<Server port="8085" shutdown="SHUTDOWN"> ... <Connector port="18080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="18443" /> ... <Connector port="8009" protocol="AJP/1.3" redirectPort="18443" /> </Server>
該項目下的web.xml文件配置以下:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <!-- ======================== 單點登陸開始 ======================== --> <!-- 用於單點退出,該過濾器用於實現單點登出功能,可選配置--> <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://dddr.cas.com:8443/cas-server/login</param-value> </init-param> <init-param> <param-name>serverName</param-name> <param-value>http://dddr.money.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://dddr.cas.com:8443/cas-server</param-value> </init-param> <init-param> <param-name>serverName</param-name> <param-value>http://dddr.money.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> <!-- ======================== 單點登陸結束 ======================== --> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
該項目的index.jsp文件:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>cas-money</title> </head> <body> 我是cas-money... </body> </html>
接着,在確保CAS服務器開啓的狀況下,在瀏覽器地址欄裏輸入 http://dddr.money.com:18080/index.jsp,會跳轉到 https://dddr.cas.com:8443/cas-server/login登陸頁面,用戶名和密碼分別輸入(用戶名:casuser,密碼:Mellon),登陸成功後會跳轉到http://dddr.money.com:18080/index.jsp的頁面。
(2)仿照上面步驟,咱們再建一個web案例,名稱爲DDDR_CAS_store。該項目下的web.xml也仿照上面的案例,注意ur要改成本身的。index.jsp爲:
<%@ page import="org.jasig.cas.client.validation.Assertion" %> <%@ page import="org.jasig.cas.client.util.AssertionHolder" %> <%@ page import="java.security.Principal" %> <%@ page import="org.jasig.cas.client.util.AbstractCasFilter" %> <%@ page import="java.util.Map" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>$Title$</title> </head> <body> 我是DDDR_CAS_store.... <hr> <dl> <dt>Your user name:</dt> <dd>一、經過getRemoteUser來獲取信息: <%= request.getRemoteUser() == null ? "null" : request.getRemoteUser() %> </dd> <br> <dd>二、經過getUserPrincipal來獲取信息: <%= request.getRemoteUser() == null ? "null" : request.getUserPrincipal() %> </dd> <br> <dd>三、經過Assertion來獲取信息:<% Assertion ass = AssertionHolder.getAssertion(); Principal p = ass.getPrincipal(); String name = p.getName(); out.print(name); %></dd> <br> <dd>四、從session中獲取Assertion對象,建議使用AssertionHolder: <% ass = (Assertion) session.getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION); String nm = ass.getPrincipal().getName(); out.print(nm); %></dd> <br> <dd> <% Map m = ass.getPrincipal().getAttributes(); out.print(m.size()); %> </dd> </dl> </body> </html>
因爲前面的應用DDDR_CAS_Money已經在CAS上登陸,所以,在瀏覽器地址欄裏輸入 http://dddr.store.com:17070/index.jsp,會直接呈現下述頁面:
如今,咱們已經實現了多個應用經過CAS實現單點登陸。接下來,咱們定製化CAS頁面,進行登陸頁與登陸方式的自定義,使得頁面呈現的效果更符合咱們想要的效果。
三.定製化CAS頁面風格
1.新建一個maven的web項目,名稱爲MyCAS_Server,將原先cas-server下的文件都拷貝到該項目的webapp文件夾下。
2.修改登陸和登出頁面的風格,而後在maven中執行package打包命令,將打出的war包替換CAS所在tomcat服務器下的cas-server便可。注意:要確保CAS的war包名稱一致。
四.CAS數據庫驗證
咱們上面進行的CAS驗證,都是基於CAS自帶的用戶名和密碼進行驗證的,若是要對接咱們的數據庫信息,首先將cas-server-4.0.0-release\cas-server-4.0.0\modules\cas-server-support-jdbc-4.0.0.jar以及對於數據庫的jar包加入到cas_server的lib目錄下。接着,修改WebRoot\WEB-INF\deployerConfigContext.xm文件,將下面代碼註釋掉:
<bean id="primaryAuthenticationHandler" class="org.jasig.cas.authentication.AcceptUsersAuthenticationHandler"> <property name="users"> <map> <entry key="casuser" value="Mellon"/> </map> </property> </bean>
根據本身的數據庫配置信息,添加以下代碼,更新爲JDBC驗證方式:
<!-- 更新爲JDBC驗證方式 開始 --> <!-- 配置數據源 --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName"><value>com.mysql.jdbc.Driver</value></property> <property name="url"><value>jdbc:mysql://localhost:3306/itszt4?characterEncoding=utf8</value></property> <property name="username"><value>root</value></property> <property name="password"><value>2018</value></property> </bean> <bean id="primaryAuthenticationHandler" class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler"> <property name="dataSource" ref="dataSource"></property> <property name="sql" value="select userpwd from user where username=?"></property> <!-- 若是須要加密,則配置加密器 ,我這裏不須要--> <!-- <property name="passwordEncoder" ref="MD5PasswordEncoder"></property> --> </bean> <!-- 添加MD5密碼加密功能 --> <bean id="MD5PasswordEncoder" class="org.jasig.cas.authentication.handler.DefaultPasswordEncoder"> <constructor-arg index="0"> <value>MD5</value> </constructor-arg> </bean> <!-- 更新爲JDBC驗證方式 結束 -->
接下來再進行CAS驗證,就改成匹配數據庫表中的數據了。