首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

CAS 集群部署實戰:基於 Tomcat-Redis-Session-Manager 實現 Session 共享與坑點排查

     編輯:Java 綜合教學

CAS 集群部署實戰:基於 Tomcat-Redis-Session-Manager 實現 Session 共享與坑點排查

CAS (Central Authentication Service) 3.x+ 採用 Spring Web Flow 管理登錄流程,依賴 Servlet Session 存儲流程狀態(execution、_eventId 等)。集群環境下,必須解決 票據共享 與 Session 共享 兩大核心問題。本文記錄基於 tomcat-redis-session-manager 實現 Session 共享的完整配置與「Session 不更新」疑難雜症的根因分析與解決方案。

運行環境

  • JDK 6 / Tomcat 7
  • CAS Server 3.x/4.x
  • Redis 2.x/3.x

核心依賴 JAR(置於 $CATALINA_HOME/lib)

  • tomcat-redis-session-manager-1.1.jar
  • jedis-2.1.0.jar
  • commons-pool-1.5.5.jar
若版本不匹配,請至 GitHub Releases 下載對應版本。

配置步驟:修改 conf/context.xml

<Context>
    <Valve className="com.orangefunction.tomcat.redissessions.RedisSessionHandlerValve" />
    <Manager className="com.orangefunction.tomcat.redissessions.RedisSessionManager"
             host="127.0.0.1"
             port="6379"
             database="0"
             maxInactiveInterval="1800" />  <!-- 30 分鐘,單位秒 -->
</Context>

重啟 Tomcat 後,Session 即自動序列化存入 Redis(Key 為 JSESSIONID)。

疑難雜症:登錄頁反覆刷新,表單不提交

現象

用戶點擊「登錄」按鈕,頁面僅刷新,無任何表單驗證動作,execution 參數始終為無效值(如 e2s1)。

根因深度追蹤

  1. Web Flow 機制:登錄頁包含隱藏字段 execution,標識當前流程狀態。提交時帶回該值,Web Flow 從 Session 中取出對應 FlowExecution 繼續流程。
  2. execution 生成邏輯:execution = "e" + conversationId + "s" + subFlowId。conversationId 來源於 Session 屬性 webflowConversationContainer 中的自增序列。
  3. Redis Session Manager 預設策略:僅在 Session 屬性引用變更(setAttribute 新 Key 或替換 Value 物件)時標記「髒數據」並寫回 Redis。直接修改物件內部字段(如 container.conversationIdSequence++)不會觸發髒標記。
  4. 後果:Web Flow 更新 webflowConversationContainer 內部狀態 → Session 物件引用未變 → Manager 認定無變化 → 不同步到 Redis → 下一請求從 Redis 讀取舊 Session → 找不到新 conversationId → 判定 execution 無效 → 重新初始化流程 → 頁面刷新循環。

驗證步驟

  • 添加 Filter 打印 session.getAttribute("webflowConversationContainer") → 內存中屬性確實已更新。
  • 直接連 Redis GET JSESSIONID → 序列化數據未變化。

解決方案(二選一)

方案一:修改髒數據判定策略(推薦,治本)

參考《Session 同步時自定義類對象屬性保存不上的解決方法》,擴展 RedisSessionManager,重寫 isSessionDirty(),採用深度比較或序列化比較檢測物件內部變更。

方案二:強制標記髒數據(快速止血)

在登錄請求前置 Filter 中強制寫入一個變化的屬性:

public class ForceSessionDirtyFilter implements Filter {
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
        HttpSession session = ((HttpServletRequest)req).getSession();
        session.setAttribute("_force_dirty_" + System.nanoTime(), "dirty"); // 每次請求新 Key
        chain.doFilter(req, res);
    }
}

在 web.xml 中映射到 /login/*。新 Key 觸發髒標記 → 整個 Session 同步到 Redis → webflowConversationContainer 內部變更隨之持久化。

生產環境補充建議

  • 啟用 Redis 集群/哨兵模式,避免單點故障。
  • 配置 maxInactiveInterval 與 CAS Ticket 過期時間一致(如 TGT 2 小時 → Session 7200 秒)。
  • 監控 Redis 記憶體佔用,設置 maxmemory-policy allkeys-lru 防止 OOM。
  • CAS 票據共享建議使用官方 cas-server-support-redis 模塊,而非自行實現。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved