CAS 是企業級單一登入 (SSO) 解決方案,支援跨應用程式的統一身分驗證。本文涵蓋伺服器端 SSL 設定、CAS Server 部署、自訂 JDBC 驗證處理器、客戶端整合與 PHP 客戶端範例。
keytool -genkeypair -alias cas -keyalg RSA -keysize 2048 \
-keystore /etc/cas/keystore -storepass changeit -keypass changeit \
-dname "CN=cas.example.com, OU=IT, O=Example, L=City, ST=State, C=TW" \
-validity 365 -ext SAN=dns:cas.example.com,dns:localhost,ip:127.0.0.1
keytool -exportcert -alias cas -keystore /etc/cas/keystore \
-storepass changeit -file /etc/cas/cas.crt -rfc
keytool -importcert -alias cas -file /etc/cas/cas.crt \
-keystore $JAVA_HOME/lib/security/cacerts -storepass changeit -noprompt
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS"
keystoreFile="/etc/cas/keystore" keystorePass="changeit"
keyAlias="cas" />
# 建立專案
mvn archetype:generate -DarchetypeGroupId=org.apereo.cas \
-DarchetypeArtifactId=cas-server-webapp-archetype \
-DarchetypeVersion=6.6.0 -DgroupId=com.example -DartifactId=cas-server \
-Dversion=1.0.0 -Dpackage=com.example.cas
# 建構 WAR
cd cas-server && mvn clean package
# 部署
cp target/cas.war $CATALINA_HOME/webapps/
# 或設定 Tomcat contextPath
CREATE TABLE users (
username VARCHAR(50) PRIMARY KEY,
password VARCHAR(255) NOT NULL, -- BCrypt 雜湊
enabled BOOLEAN DEFAULT TRUE
);
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource"
destroy-method="close">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://db:3306/cas?useSSL=false&serverTimezone=Asia/Taipei" />
<property name="username" value="cas_user" />
<property name="password" value="${cas.db.password}" />
</bean>
<bean class="org.apereo.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler">
<property name="sql" value="SELECT password FROM users WHERE username=? AND enabled=TRUE" />
<property name="dataSource" ref="dataSource" />
<property name="passwordEncoder" ref="passwordEncoder" />
</bean>
<bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />
<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://cas.example.com:8443/cas/login</param-value>
</init-param>
<init-param>
<param-name>serverName</param-name>
<param-value>https://app.example.com:8443</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CASFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 驗證票證 Filter -->
<filter>
<filter-name>CASValidationFilter</filter-name>
<filter-class>org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter</filter-class>
<init-param>
<param-name>casServerUrlPrefix</param-name>
<param-value>https://cas.example.com:8443/cas</param-value>
</init-param>
<init-param>
<param-name>serverName</param-name>
<param-value>https://app.example.com:8443</param-value>
</init-param>
</filter>
# application.yml
cas:
server-url-prefix: https://cas.example.com:8443/cas
server-login-url: https://cas.example.com:8443/cas/login
client-host-url: https://app.example.com:8443
# 依賴
implementation "org.apereo.cas:cas-client-support-springboot:3.6.0"
require_once 'CAS/CAS.php';
phpCAS::client(CAS_VERSION_2_0, 'cas.example.com', 8443, '/cas');
phpCAS::setNoCasServerValidation(); // 開發環境跳過 SSL 驗證
phpCAS::forceAuthentication();
$user = phpCAS::getUser(); // 取得登入帳號
// 登出
if (isset($_GET['logout'])) {
phpCAS::logout();
}
| 現象 | 可能原因 | 解決方向 |
|---|---|---|
| SSL 手震失敗 | 憑證不受信、主機名不符 | 檢查 SAN、信任存儲、clientAuth 設定 |
| JDBC 驗證失敗 | SQL 錯誤、密碼編碼不符 | 啟用 SQL 日誌、確認 BCrypt 雜湊 |
| 重導向迴圈 | serverName 不匹配、Cookie 網域 | 統一 serverName、設定 cookie domain |
| 登出不生效 | 單一登出 (SLO) 未正確配置 | 啟用 CAS Client SingleSignOutFilter |