實現用戶在同一 Tomcat 實例下,登入一次即可存取多個 Web 應用,無需重複認證。
編輯 $CATALINA_HOME/conf/server.xml,在 <Host> 元素下加入:
<Valve className="org.apache.catalina.authenticator.SingleSignOn"
debug="0"
requireReauthentication="false" />
requireReauthentication="false":允許跨應用共享認證憑證(預設即為 false)。debug="0":關閉詳細日誌,生產環境建議保持 0。Tomcat 透過 Realm 讀取用戶與角色資訊。常見實作:
MemoryRealm:tomcat-users.xml(開發測試用)JDBCRealm / DataSourceRealm:關係型資料庫JNDIRealm:LDAP / Active DirectoryJDBCRealm 範例:
<Realm className="org.apache.catalina.realm.JDBCRealm"
driverName="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/mydb?useSSL=false"
connectionName="dbuser"
connectionPassword="dbpass"
userTable="users"
userNameCol="username"
userCredCol="password"
userRoleTable="user_roles"
roleNameCol="role_name" />
資料表結構需包含 users(username, password) 以及 user_roles(username, role_name)。
在各 Web 應用的 WEB-INF/web.xml 加入:
<security-constraint>
<web-resource-collection>
<web-resource-name>Protected Area</web-resource-name>
<url-pattern>/*</url-pattern> <!-- 全站保護 -->
</web-resource-collection>
<auth-constraint>
<role-name>intrauser</role-name> <!-- 僅允許此角色 -->
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>FORM</auth-method> <!-- 或 BASIC, DIGEST, CLIENT-CERT -->
<realm-name>Intra SSO Realm</realm-name> <!-- 所有參與 SSO 的應用必須相同 -->
<form-login-config>
<form-login-page>/login.jsp</form-login-page>
<form-error-page>/login-error.jsp</form-error-page>
</form-login-config>
</login-config>
<security-role>
<role-name>intrauser</role-name>
</security-role>
關鍵點:
realm-name 必須跨應用一致,否則 SSO 失效。auth-method 建議使用 FORM 自訂登入頁,體驗優於 BASIC 的瀏覽器彈窗。容器認證後,Servlet 可透過:
String username = request.getRemoteUser(); // 用戶名
Principal principal = request.getUserPrincipal(); // Principal 物件
boolean isInRole = request.isUserInRole("admin"); // 角色檢查
無需自行維護 Session 屬性,容器自動管理 SSO Session。
若需跨多個 Tomcat(甚至異構容器)實現 SSO,建議架設前端反向代理(如 Apache HTTPd + mod_auth_openidc、Nginx + Lua、或 Keycloak/CAS 等身分識別提供者),在代理層統一認證,再透過 Header(如 X-Remote-User)傳遞身分至後端應用。