CAS 實現 SSO 單點登入
環境
cas-server-4.1.8,cas-client-3.4.0,Java-8,Maven-3,Tomcat-7.0.72
CAS Server 安裝
點此進入 CAS 下載列表,選擇下載 cas-4.1.8.zip。
https://github.com/apereo/cas/releases
解壓縮 cas-4.1.8.zip 並進入 cas-server-webapp 目錄,在當前目錄開啟 cmd 並執行安裝命令。
mvn -e -ff clean install -Dmaven.test.skip=true
經親身測試(自己拉的電信12M網路),該安裝過程非常漫長,主要因為映象原因導致依賴包下載非常慢,此過程需靜心等待。或直接下載我已經打好包的 cas.war 檔案(注:該檔案的依賴包版本有稍做修改,此不影響正常使用)。
安裝完成後,在 cas-server-webapp/target 目錄下可以看到 cas.war 檔案,該檔案便是 cas server 應用服務的 war 包。
cas server 安全認證是基於 https 的,這裡使用 JDK 自帶的 keytool 工具生成數字證書,生產環境系統的應用需要到證書提供商處購買證書。證書的生成及 Tomcat 的配置可參考文章:keytool 生成數字證書 – tomcat https 配置 。
https://fanlychie.github.io/post/java-keytool-tomcat-https.html
首先確保 Tomcat 的 https 可以正常訪問,將 cas.war 檔案拷貝到 apache-tomcat-7.0.72/webapps 下進行釋出,啟動 Tomcat,訪問 https://www.fanlychie.com:8443/cas。
上圖是用火狐瀏覽器開啟的連結,選擇高階 -> 新增例外 -> 確認安全例外。
使用者名稱和密碼在 apache-tomcat-7.0.72/webapps/cas/WEB-INF/deployerConfigContext.xml 配置檔案中,找到並開啟該檔案,大概在 105 行
<bean id="primaryAuthenticationHandler"
class="org.jasig.cas.authentication.AcceptUsersAuthenticationHandler">
<property name="users">
<map>
<entry key="casuser" value="Mellon" />
</map>
</property>
</bean>
可以看到預設的使用者名稱是 casuser,密碼是 Mellon。
看到上圖的頁面,表明 cas server 已經部署成功。
CAS Server 配置基於資料庫使用者認證
回到 cas-4.1.8.zip 解壓縮的目錄,並進入 cas-server-support-jdbc 目錄,在當前目錄開啟 cmd 並執行安裝命令
mvn -e -ff clean install -Dmaven.test.skip=true
安裝完成後在 target 目錄得到 cas-server-support-jdbc-4.1.8.jar 檔案。
將該檔案拷貝到 apache-tomcat-7.0.72/webapps/cas/WEB-INF/lib 目錄下,並向此目錄新增 c3p0-0.9.1.2.jar,mysql-connector-java-5.1.17.jar 兩個檔案。嫌麻煩的話,點此下載這三個 jar 包的壓縮包檔案。
http://pan.baidu.com/s/1pLIrdWn
再次開啟 apache-tomcat-7.0.72/webapps/cas/WEB-INF/deployerConfigContext.xml 檔案,大概在第 54 行。
<bean id="authenticationManager" class="org.jasig.cas.authentication.PolicyBasedAuthenticationManager">
<constructor-arg>
<map>
<!--
| IMPORTANT
| Every handler requires a unique name.
| If more than one instance of the same handler class is configured, you must explicitly
| set its name to something other than its default name (typically the simple class name).
-->
<entry key-ref="proxyAuthenticationHandler" value-ref="proxyPrincipalResolver" />
<!-- 登出此項
<entry key-ref="primaryAuthenticationHandler" value-ref="primaryPrincipalResolver" />
-->
<!-- 新增此項 -->
<entry key-ref="myAuthenticationHandler" value-ref="primaryPrincipalResolver" />
</map>
</constructor-arg>
<!-- Uncomment the metadata populator to capture the password.
<property name="authenticationMetaDataPopulators">
<util:list>
<bean class="org.jasig.cas.authentication.CacheCredentialsMetaDataPopulator"/>
</util:list>
</property>
-->
<!--
| Defines the security policy around authentication. Some alternative policies that ship with CAS:
|
| * NotPreventedAuthenticationPolicy - all credential must either pass or fail authentication
| * AllAuthenticationPolicy - all presented credential must be authenticated successfully
| * RequiredHandlerAuthenticationPolicy - specifies a handler that must authenticate its credential to pass
-->
<property name="authenticationPolicy">
<bean class="org.jasig.cas.authentication.AnyAuthenticationPolicy" />
</property>
</bean>
按以上配置登出掉第二個 entry 並新增一個 entry。接著在後面新增兩個 bean 配置。
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/cas_test_db?autoReconnect=true&useUnicode=true&characterEncoding=utf-8" />
<property name="user" value="root" />
<property name="password" value="root" />
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="initialPoolSize" value="10" />
<property name="maxIdleTime" value="1800" />
<property name="maxPoolSize" value="60" />
<property name="acquireIncrement" value="5" />
<property name="acquireRetryAttempts" value="60" />
<property name="acquireRetryDelay" value="2000" />
<property name="breakAfterAcquireFailure" value="false" />
<property name="autoCommitOnClose" value="false" />
<property name="checkoutTimeout" value="30000" />
<property name="idleConnectionTestPeriod" value="900" />
</bean>
<bean id="myAuthenticationHandler" class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler"
p:dataSource-ref="dataSource"
p:sql="SELECT passwd FROM user WHERE name = ?" />
其中 cas_test_db 資料庫中的 user 建表語句為
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`passwd` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
)
重啟 Tomcat,訪問 https://www.fanlychie.com:8443/cas,用資料庫中的 name/passwd 作為使用者名稱和密碼登入系統,若登入成功,表明配置已成功。
CAS Client 客戶端使用和配置
使用 maven 建立兩個 web 專案 cas-client1,cas-client2。點此下載 demo 檔案。
cas-client1 專案 pom.xml 配置
<dependencies>
<dependency>
<groupId>org.jasig.cas.client</groupId>
<artifactId>cas-client-core</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.12</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<path>/</path>
<port>8881</port>
<httpsPort>8081</httpsPort>
<uriEncoding>UTF-8</uriEncoding>
<protocol>org.apache.coyote.http11.Http11NioProtocol</protocol>
<clientAuth>false</clientAuth>
<keystoreFile>C:\Users\fanlychie\.keystore\selfissue.jks</keystoreFile>
<keystorePass>123654</keystorePass>
<keystoreType>JKS</keystoreType>
<url>http://localhost:8081/manager/html</url>
</configuration>
</plugin>
</plugins>
</build>
首先必須確保專案 https 協議可以正常訪問,否則 cas server 無法認證。
選中專案 -> Run As -> Maven build… -> tomcat7:run
訪問 https://www.fanlychie.com:8081,若能訪問到,表明 Tomcat 已準備好。
cas-client1 專案 web.xml 配置
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<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>
<init-param>
<param-name>casServerUrlPrefix</param-name>
<!-- 此處配置的是 cas server 地址 -->
<param-value>https://www.fanlychie.com:8443/cas</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CAS Single Sign Out Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<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>
<!-- 此處配置的是 cas server 登入地址 -->
<param-value>https://www.fanlychie.com:8443/cas/login</param-value>
</init-param>
<init-param>
<param-name>serverName</param-name>
<!-- 此處配置的是當前專案地址, 且必須使用 https 服務, 否則 cas server 無法認證 -->
<param-value>https://www.fanlychie.com:8081</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CAS Authentication Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<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>
<!-- 此處配置的是 cas server 地址 -->
<param-value>https://www.fanlychie.com:8443/cas</param-value>
</init-param>
<init-param>
<param-name>serverName</param-name>
<!-- 此處配置的是當前專案地址, 且必須使用 https 服務, 否則 cas server 無法認證 -->
<param-value>https://www.fanlychie.com:8081</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CAS Validation Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<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>
<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>
以上是 cas client 標準配置,具體資訊可參考 https://github.com/apereo/java-cas-client。
cas-client2 配置基本與 cas-client1 配置相同,詳情可見 demo,同時啟動這兩個專案
-
cas-client1 - https://www.fanlychie.com:8081
-
cas-client2 - https://www.fanlychie.com:8082
訪問其中的一個專案 https://www.fanlychie.com:8081,會自動跳到
https://www.fanlychie.com:8443/cas/login?service=https%3A%2F%2Fwww.fanlychie.com%3A8081%2F。
由於還沒有登入過 CAS 認證系統,CAS 認證系統攔截到你的訪問,進入到認證系統登入介面,當登入成功後,CAS 服務會跳轉向到你剛剛訪問的地址。
當你訪問 https://www.fanlychie.com:8082,此時是不需要登入了的。
至此,CAS 實現 SSO 單點登入系統搭建結束。