囉嗦幾句:證書是單點登陸認證系統中很重要的一把鑰匙,客戶端於服務器的交互安全靠的就是證書;本教程因爲是演示因此就本身用JDK自帶的keytool工具生成證書;若是之後真正在產品環境中使用確定要去證書提供商去購買,證書認證通常都是由VeriSign認證,中文官方網站:http://www.verisign.com/cn/ html
用JDK自帶的keytool工具生成證書: java
keytool -genkey -alias wsria -keyalg RSA -keystore d:/keys/wsriakey
無圖不給力,有圖有真相: mysql
具體的輸入項圖片中都有說明,有一點我要解釋一下;在輸入完密碼後提示輸入域名是我輸入的是sso.wsria.com,其實這個域名是不存在的,可是我爲了演示因此虛擬了這個域名,技巧在於修改 linux
C:\Windows\System32\drivers\etc\hosts
添加內容以下: git
127.0.0.1 sso.wsria.com
這樣在訪問sso.wsria.com的時候實際上是訪問的127.0.0.1也就是本機 程序員
嚴重提醒:提示輸入域名的時候不能輸入IP地址 github
D:\keys>keytool -export -file d:/keys/wsria.crt -alias wsria -keystore d:/keys/wsriakey
特別提示:若是提示: web
keytool error: java.io.IOException: Keystore was tampered with, or password was incorrect
那麼請輸入密碼:changeit 算法
來點顏色: spring
至此導出證書完成,能夠分發給應用的JDK使用了,接下來說解客戶端的JVM怎麼導入證書。
keytool -import -keystore D:\tools\jdk\1.6\jdk1.6.0_20\jre\lib\security\cacerts -file D:/keys/wsria.crt -alias wsria
來點顏色瞧瞧:
D:\tools\jdk\1.6\jdk1.6.0_20\jre\lib\security -- 是jre的目錄;密碼仍是剛剛輸入的密碼。至此證書的建立、導出、導入到客戶端JVM都已完成,下面開始使用證書到Web服務器中,本教程使用tomcat。
說是應用起始作的事情就是啓用Web服務器(Tomcat)的SSL,也就是HTTPS加密協議,爲何加密我就不用囉嗦了吧…… 準備好一個乾淨的tomcat,本教程使用的apache-tomcat-6.0.29 打開tomcat目錄的conf/server.xml文件,開啓83和87行的註釋代碼,並設置keystoreFile、keystorePass修改結果以下:
1
2
|
<connectorport="8443"protocol="HTTP/1.1"sslenabled="true"maxthreads="150"scheme="https"secure="true"clientauth="false"sslprotocol="TLS"keystorefile="D:/keys/wsriakey"keystorepass="wsria.com">
</connector>
|
好了,到此Tomcat的SSL啓用完成,如今你能夠啓動tomcat試一下了,例如本教程輸入地址:https://sso.wsria.com:8443/ 打開的是:
好的,那麼咱們點擊「繼續瀏覽此網站(不推薦)。如今進入Tomcat目錄了吧,若是是那麼你又向成功邁進了一步。
OK,接下來要配置CAS服務器了。
CAS服務端下載:http://www.jasig.org/cas/download
下載完成後將cas-server-3.4.3.1.zip解壓,解壓cas-server-3.4.3/modules/cas-server-webapp-3.4.3.1.war,更名爲cas,而後複製cas目錄到你的tomcat/webapp目錄下
如今能夠訪問CAS應用了,固然要使用HTTPS加密協議訪問,例如本教程地址:https://sso.wsria.com:8443/cas/login ,如今打開了CAS服務器的頁面輸入admin/admin點擊登陸(CAS默認的驗證規則只要用戶名和密碼相同就經過)因此若是你看到下面的這張圖片你就成功了
你成功了嗎?若是沒有成功請再檢查以上步驟!
使用cmd或者shell進入cas-server-3.4.10目錄,運行:
1
|
mvn package -pl cas-server-webapp,cas-server-support-jdbc
|
意思是隻須要構建cas-server-webapp和cas-server-support-jdbc,若是須要其餘的請根據文件夾名稱設置或者構建所有模塊,打包所有模塊命令:mvn package 便可。打包過程當中會從網絡下載須要的jar包,請耐心等待;若是在~/.m2/settings.xml中定義了mirror代理,那麼請把隨便修改一個字符,不然下載jar包會失敗!
打包完成後就能夠從cas-server-webapp/target/cas.war複製到你的tomcat/webapp中;或者直接複製cas-server-webapp/target/cas-server-webapp-3.4.10目錄到tomcat/webapp目錄下,其餘步驟和上面同樣。
上面的初體驗僅僅是簡單的身份驗證,實際應用中確定是要讀取數據庫的數據,下面咱們來進一步配置CAS服務器怎麼讀取數據庫的信息進行身份驗證。 首先打開
tomcat/webapp/cas/WEB-INF/deployerConfigContext.xml配置的地方以下:
找到第92行處,註釋掉:SimpleTestUsernamePasswordAuthenticationHandler這個驗證Handler,這個是比較簡單的,只是判斷用戶名和密碼相同便可經過,這個確定不能在實際應用中使用,棄用!
註釋掉92行後在下面添加下面的代碼:
1
2
3
4
5
|
<beanclass="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler">
<propertyname="dataSource"ref="dataSource"></property>
<propertyname="sql"value="select password from t_admin_user where login_name=?"></property>
<propertyname="passwordEncoder"ref="MD5PasswordEncoder"></property>
</bean>
|
在文件的末尾以前加入以下代碼:
1
2
3
4
5
6
7
8
9
10
11
12
|
<beanid="dataSource"class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<propertyname="driverClassName"><value>com.mysql.jdbc.Driver</value></property>
<propertyname="url"><value>jdbc:
mysql:///wsriademo</value></property>
<propertyname="username"><value>root</value></property>
<propertyname="password"><value>root</value></property>
</bean>
<beanid="MD5PasswordEncoder"class="org.jasig.cas.authentication.handler.DefaultPasswordEncoder">
<constructor-argindex="0">
<value>MD5</value>
</constructor-arg>
</bean>
|
複製cas-server-3.4.3.1\modules\cas-server-support-jdbc-3.4.3.1.jar和mysql驅動jar包到tomcat/webapp/cas/WEB-INF/lib目錄
QueryDatabaseAuthenticationHandler,是cas-server-support-jdbc提供的查詢接口其中一個,QueryDatabaseAuthenticationHandler是經過配置一個 SQL 語句查出密碼,與所給密碼匹配
dataSource,我就不用解釋了吧,就是使用JDBC查詢時的數據源
sql,語句就是查詢哪一張表,本例根據t_admin_user表的login_name字段查詢密碼,CAS會匹配用戶輸入的密碼,若是匹配則經過;下面是t_admin_user的表結構:
1
2
3
4
5
6
7
8
|
createtablet_admin_user (
idbigintnotnullauto_increment,
emailvarchar(255),
login_namevarchar(255)notnullunique,
namevarchar(255),
passwordvarchar(255),
primarykey(id)
) ENGINE=InnoDB;
|
添加cas-client的jar包,有兩種方式:
下載cas-client,地址:http://www.ja-sig.org/downloads/cas-clients/,而後解壓cas-client-3.1.12.zip,在modules文件夾中有須要的jar包,請根據本身的項目狀況選擇使用
用maven打包server的方式同樣,在cas-client-3.2.1目錄中運行命令:
1
|
mvn package -pl cas-client-core -DskipTests=true
|
而後從target目錄中複製cas-client-core-3.2.1.jar到應用的WEB-INF/lib目錄中
1
2
3
4
5
|
<dependency>
<groupid>org.jasig.cas.client</groupid>
<artifactid>cas-client-core</artifactid>
<version>3.1.12</version>
</dependency>
|
編輯web.xml,而後粘貼下面的代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
|
<!-- 用於單點退出,該過濾器用於實現單點登出功能,可選配置-->
<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>CASFilter</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/login</param-value>
</init-param>
<init-param>
<!--這裏的server是服務端的IP-->
<param-name>serverName</param-name>
<param-value>
http://localhost:10000</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CASFilter</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://sso.wsria.com:8443/cas</param-value>
</init-param>
<init-param>
<param-name>serverName</param-name>
<param-value>
http://localhost:10000</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>
<!-- 自動根據單點登陸的結果設置本系統的用戶信息 -->
<filter>
<display-name>AutoSetUserAdapterFilter</display-name>
<filter-name>AutoSetUserAdapterFilter</filter-name>
<filter-class>com.wsria.demo.filter.AutoSetUserAdapterFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>AutoSetUserAdapterFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- ======================== 單點登陸結束 ======================== -->
|
每一個Filter的功能我就很少說了,都有註釋的,關鍵要解釋一下AutoSetUserAdapterFilter的做用和原理. 查看完整的web.xml請 猛擊這裏
先看一下這個AutoSetUserAdapterFilter.java的源碼
好的,若是你是老程序員應該很快就清楚Filter的目的,若是不太懂我再講解一下; 主要是經過CAS的const_cas_assertion獲取從CAS服務器登錄的用戶名,而後再根據系統內部的用戶工具(UserUtil.java)來判斷是否已經登陸過,若是沒有登陸根據登陸名從數據庫查詢用戶信息,最後使用設置把用戶信息設置到當前session中。 這樣就把用戶信息保存到了Sessino中,咱們就能夠經過UserUtil工具來獲取當前登陸的用戶了,我在實例項目中也加入了此功能演示,請看代碼:main.jsp的第44行處
若是是爲一個老項目添加單點登陸功能,那麼基本不須要其餘的修改,設置好上面的filter便可;固然最好獲取用戶信息的地方都調用一個工具類,統一管理不容易出錯。
這個比較簡單,把你的退出連接設置爲:https://sso.wsria.com/cas/logout 便可。
CAS服務端(cas-server)的界面只能在測試的時候用一下,真正系統上線確定須要定製開發本身的頁面,就像網易和CSDN的統一認證平臺同樣,全部子系統的認證都經過此平臺來轉接,你們能夠根據他們的頁面本身定製出適合所屬應用或者公司的界面;簡單介紹一下吧,複製 cas\WEB-INF\view\jsp\default\ui的一些JSP文件,每個文件的用途文件名已經區分了,本身修改了替換一下就能夠了。 例如:
花了一下午時間終於寫完了,總共十項也算完美了。 如今看來起始利用CAS實現單點登陸其實不難,不要畏懼,更不要排斥! 本教程後面的代碼部分均來自http://code.google.com/p/wsria的項目分支wsria-demo-sso
到此本教程所有結束,但願看完後對你有幫助,若是有幫助還望繼續推薦給其餘人,有說明意見或者問題請回復或者IM聯繫我。
若是遇到了意料以外的問題請參考文章的評論部分,或許能找到問題的緣由以及解決辦法!
因爲建立證書的域名和在應用中配置的cas服務域名不一致致使如下錯誤,詳細請參考:
因爲建立證書的域名和在應用中配置的cas服務域名不一致致使如下錯誤: SEVERE: javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No name matching casserver found javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No name matching casserver found at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1731) at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:241) at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:235) at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1206) at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:136) at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:593) at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.java:529) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:925) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1170) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1197) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1181) at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:434) at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:166) at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1172) at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:234) at org.jasig.cas.client.validation.AbstractCasProtocolUrlBasedTicketValidator.retrieveResponseFromServer(AbstractCasProtocolUrlBasedTicketValidator.java:35) at org.jasig.cas.client.validation.AbstractUrlBasedTicketValidator.validate(AbstractUrlBasedTicketValidator.java:178) at org.jasig.cas.client.validation.AbstractTicketValidationFilter.doFilter(AbstractTicketValidationFilter.java:132) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.jasig.cas.client.authentication.AuthenticationFilter.doFilter(AuthenticationFilter.java:111) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.jasig.cas.client.session.SingleSignOutFilter.doFilter(SingleSignOutFilter.java:99) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298) at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:859) at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588) at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489) at java.lang.Thread.run(Thread.java:662) Caused by: java.security.cert.CertificateException: No name matching casserver found at sun.security.util.HostnameChecker.matchDNS(HostnameChecker.java:210) at sun.security.util.HostnameChecker.match(HostnameChecker.java:77) at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:264) at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:250) at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1185) ... 32 more Feb 1, 2012 10:01:28 PM org.jasig.cas.client.validation.AbstractTicketValidationFilter doFilter WARNING: org.jasig.cas.client.validation.TicketValidationException: The CAS server returned no response. org.jasig.cas.client.validation.TicketValidationException: The CAS server returned no response. at org.jasig.cas.client.validation.AbstractUrlBasedTicketValidator.validate(AbstractUrlBasedTicketValidator.java:181) at org.jasig.cas.client.validation.AbstractTicketValidationFilter.doFilter(AbstractTicketValidationFilter.java:132) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.jasig.cas.client.authentication.AuthenticationFilter.doFilter(AuthenticationFilter.java:111) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.jasig.cas.client.session.SingleSignOutFilter.doFilter(SingleSignOutFilter.java:99) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298) at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:859) at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588) at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489) at java.lang.Thread.run(Thread.java:662)
整整一年以後由於須要爲客戶搭建CAS換季再次更新本文章,不知道碰巧呢碰巧呢仍是碰巧呢,反正就是11.5號了…… 在這裏還要感謝你們對個人支持,要否則這篇教程也不會一直處於本博客的第一位……
不知道從哪一個版本開始cas全面使用了maven構建項目,因此須要安裝apache maven工具來構建源碼,下面step by step講解如何構建(面向沒有接觸過maven的童鞋)
下載Maven:打開http://maven.apache.org/download.html後下載對應的包,windows用戶請下載Binary zip格式的壓縮包,linux或者unix用戶請下載Binary tar.gz**格式的壓縮包
安裝、配置Maven:解壓壓縮包到一個目錄,例如/home/kafeitu/tools/apache/apache-maven-3.0.3,而後設置系統環境變量M3_HOME=/home/kafeitu/tools/apache/apache-maven-3.0.3,在PAT變量中添加路徑
驗證安裝:從新打開一個命令窗口,
1
|
source.bashrc
|
1
|
source/etc/profile
|
在cmd或者shell中進入解壓的cas server目錄後運行:mvn -version後若是看到打印系統信息和maven版本信息後證實配置ok
你也能夠申請免費的StartSSL CA證書: StartSSL(公司名:StartCom)也是一家CA機構,它的根證書好久以前就被一些具備開源背景的瀏覽器支持(Firefox瀏覽器、谷歌Chrome瀏覽器、蘋果Safari瀏覽器等)。 申請地址:http://www.startssl.com 申請方法參考:http://www.linuxidc.com/Linux/2011-11/47478.htm