keycloak~token配置相關說明

张占岭發表於2024-10-23

會話有效期

在 Keycloak 中,"SSO Session Idle" 和 "SSO Session Max" 是用於配置單點登入(SSO)會話的兩個引數。這兩個引數影響使用者在系統中的會話過期和最大有效時間。

  1. SSO Session Idle(單點登入會話空閒時間):

    • 定義: 表示使用者在系統中沒有活動的時間閾值。如果使用者在這段時間內沒有與系統進行互動,那麼他們的單點登入會話就被視為處於空閒狀態。

    • 實際意義: 當使用者登入後,在一段時間內沒有進行任何操作,系統會認為使用者不再活躍,這時候可以選擇在一定的時間後自動登出使用者,以提高安全性。例如,設定為 30 分鐘,如果使用者在 30 分鐘內沒有任何操作,他們的會話將被認為是空閒的,可以選擇要求使用者重新驗證身份。

  2. SSO Session Max(單點登入會話最大時間):

    • 定義: 表示使用者單點登入會話的最大有效時間。即使使用者一直在系統中活躍,當達到此時間閾值後,他們的會話也會被強制登出。

    • 實際意義: 即使使用者一直在系統中活躍,為了安全和資源管理的目的,可以設定一個最大時間,超過這個時間後,使用者將被強制重新登入,以確保他們的身份驗證狀態是最新的。例如,設定為 8 小時,使用者的會話將在 8 小時後過期,需要重新登入。

這兩個引數通常與安全性和使用者體驗的平衡相關。設定得太短可能導致使用者頻繁需要重新登入,而設定得太長可能增加安全風險。具體的設定應該根據你的應用程式的安全需求和使用者行為來確定。

Client Session有效期

"Client Session Idle" 和 "Client Session Max" 是 Keycloak 中用於配置客戶端會話的兩個引數。這兩個引數影響與客戶端相關的會話過期和最大有效時間。

  1. Client Session Idle(客戶端會話空閒時間):

    • 定義: 表示使用者與特定客戶端之間沒有活動的時間閾值。如果使用者在這段時間內沒有與特定客戶端進行互動,那麼與該客戶端關聯的會話就被視為處於空閒狀態。

    • 實際意義: 當使用者與特定客戶端建立了會話後,在一段時間內沒有與該客戶端進行任何操作,系統會認為使用者與該客戶端的會話是空閒的。這可以用於自動登出與客戶端的會話,以提高安全性。

  2. Client Session Max(客戶端會話最大時間):

    • 定義: 表示使用者與特定客戶端的會話的最大有效時間。即使使用者一直在與特定客戶端進行互動,當達到此時間閾值後,與該客戶端關聯的會話也會被強制登出。

    • 實際意義: 即使使用者與特定客戶端一直在活躍,為了安全和資源管理的目的,可以設定一個最大時間,超過這個時間後,與該客戶端關聯的會話將被強制結束,使用者可能需要重新進行身份驗證。

這兩個引數通常與客戶端相關的會話管理和安全性相關。設定得太短可能導致使用者頻繁需要重新進行身份驗證,而設定得太長可能增加安全風險。具體的設定應該根據你的應用程式的安全需求和使用者行為來確定。

會話有效期誰小用誰

在 Keycloak 中,會話的有效期確實是由這些引數中的最小值決定的。換句話說,如果設定了 "SSO Session Idle"、"SSO Session Max"、"Client Session Idle" 和 "Client Session Max",則會話將在這些引數中的最小值所定義的時間段內過期。

這種行為是為了確保會話的有效期在所有相關配置中都被嚴格限制,以提供更加精確的控制。這也意味著無論是整體的單點登入會話有效期還是與特定客戶端關聯的會話有效期,都將受到最小值的限制。

空閒會話

空閒時間這塊,keycloak14.0.0有些bug,這塊我進行了原始碼調整,當session max和session idle不同時,使用者在session idle時間內不操作,使用者會話也會超時。

在Keycloak中,有四個與空閒會話(Idle Session)相關的設定引數。它們的作用和關係如下:

  1. Offline Session Idle(領域設定):這是Keycloak的領域設定中的一個引數,用於定義空閒會話的超時時間。當使用者在一段時間內沒有與Keycloak進行任何互動時,會話會被視為處於空閒狀態。預設情況下,該引數設定為30天。

  2. Offline Session Max Limited(領域設定):這是Keycloak的領域設定中的一個引數,用於定義空閒會話的最大持續時間。該引數定義了會話的最長持續時間,從會話開始到會話終止的時間段,以秒為單位。超過這個時間段後,會話將被標記為過期,並將被銷燬。預設情況下,該引數也設定為30天。

  3. Offline Session Max(領域設定):這是Keycloak的客戶端設定中的一個引數,用於定義特定客戶端的空閒會話的最大持續時間。每個客戶端可以具有自己的空閒會話最大持續時間,以使具有不同需求的客戶端具有不同的會話時間。預設情況下,它繼承自領域的 "Offline Session Max Limited" 值。

  4. Client Offline Session Idle(客戶端設定):這是Keycloak的客戶端設定中的一個引數,用於定義特定客戶端的空閒會話的超時時間。每個客戶端可以具有自己的空閒會話超時時間,以使具有不同需求的客戶端具有不同的會話時間。預設情況下,它繼承自領域的 "Offline Session Idle" 值。

這些引數共同用於控制空閒會話的超時和最大持續時間。"Offline Session Idle" 和 "Client Offline Session Idle" 確定了使用者在沒有與Keycloak進行任何互動時,會話被認為是空閒的時間。而 "Offline Session Max Limited" 和 "Offline Session Max" 確定了會話可以持續的最長時間。如果會話超過這個時間段,它將被銷燬。

請注意,領域設定中的引數適用於整個領域(realm),而客戶端設定中的引數適用於特定的客戶端。透過為每個客戶端設定不同的值,您可以針對不同的客戶端應用程式調整會話時間。

關於會話空閒時間的bug修改

驗證token邏輯,解析session idle和session max的邏輯

  • org.keycloak.services.managers.AuthenticationManager.isSessionValid
  • SessionTimeoutHelper.IDLE_TIMEOUT_WINDOW_SECONDS是個時間戳口,它是120秒,為了解決叢集環境下的時間差問題
  public static boolean isSessionValid(RealmModel realm, UserSessionModel userSession) {
  if (userSession == null) {
    logger.debug("No user session");
    return false;
  }
  int currentTime = Time.currentTime();

  // Additional time window is added for the case when session was updated in different DC 
  // and the update to current DC was postponed
  int maxIdle = userSession.isRememberMe() && realm.getSsoSessionIdleTimeoutRememberMe() > 0 ?
      realm.getSsoSessionIdleTimeoutRememberMe() : realm.getSsoSessionIdleTimeout();
  int maxLifespan = userSession.isRememberMe() && realm.getSsoSessionMaxLifespanRememberMe() > 0 ?
      realm.getSsoSessionMaxLifespanRememberMe() : realm.getSsoSessionMaxLifespan();

  boolean sessionIdleOk =
      maxIdle > currentTime - userSession.getLastSessionRefresh() - SessionTimeoutHelper.IDLE_TIMEOUT_WINDOW_SECONDS;
  boolean sessionMaxOk = maxLifespan > currentTime - userSession.getStarted();
  return sessionIdleOk && sessionMaxOk;
}

session idle和session max的邏輯生效,如果修改refresh_token生成時的校驗邏輯

  • 將verifyRefreshToken方法引數中的checkExpiration改成false
public RefreshResult refreshAccessToken(KeycloakSession session, UriInfo uriInfo, ClientConnection connection,
                                          RealmModel realm, ClientModel authorizedClient,
                                          String encodedRefreshToken, EventBuilder event, HttpHeaders headers,
                                          HttpRequest request) throws OAuthErrorException {

    // TODO: 完善實現了線上校驗時,將引數checkExpiration從true改為false,session idle和session max的功能,
    // 但session idle到期後會話會提前登出,不會等session max到期
    RefreshToken refreshToken =
        verifyRefreshToken(session, realm, authorizedClient, request, encodedRefreshToken, false);

    event.user(refreshToken.getSubject()).session(refreshToken.getSessionState())
        .detail(Details.REFRESH_TOKEN_ID, refreshToken.getId())
        .detail(Details.REFRESH_TOKEN_TYPE, refreshToken.getType());

session idle(空閒過期時間)和session max(最大過期時間)不相等時,產生的問題

  1. session idle會作為重新整理token的過期時間
  2. 當這個時間到達後,不能再重新整理token了,但是,session還是線上的
  3. 是否需要在到達這個時間後,將會話刪除?
  4. 如果真要刪除的話,可能產生的問題就是session max的時間還沒到,但是session已經被刪除了,這樣就會導致session max的時間不準確了
  5. 但如果session idle到達,並且token沒有成功重新整理,這說明使用者空閒了,這時session是可以刪除的,與4不矛盾
  6. 解決方法
    *[x] 在session idle到達後,將session刪除,應該就解決問題了
    *[x] 或者在生成code之前,判斷它的session idle是否到期,如果到期,將會話刪除,不能生成code

keycloak關於刪除過期會話的排程

  • org.keycloak.services.scheduled.ScheduledTaskRunner # 每5執行一次
    • org.keycloak.services.scheduled.ClearExpiredUserSessionsTask
      • org.keycloak.models.map.authSession.removeExpired
      • 需要新增空間過期時間的判斷,如果到期,就刪除會話
      • 這塊需要看如何手動清除,因為預設的,infinispan中的session有自己的過期時間,按著過期時間自動清除的
      • 咱們相當於,如何讓它按著咱們的時間(這個時間經過了session idle的時間)來清除的
  • 透過上面的分析,直接從infinispan中獲取過期的session,並刪除不太可能,人家通知初始化的過期時間自行維護的,而且這種過期時間,是session
    max,而咱們的過期時間是可變的,它可能是一個session idle,也可能是session max,這與使用者是否在idle時間內是否有操作有關

生成code時,新增session idle的判斷

  • 如果不新增這個判斷,將會出現的問題是,當session idle和session max設定不同時,當session
    idle到期後,使用者的會話不會被刪除,導致重新整理token和申請code碼換token,兩塊產生的token邏輯不一樣,最終效果就是,code可以換回來token,但token在校驗時是
    session not active這樣的錯誤。
  • org.keycloak.protocol.AuthorizationEndpointBase.createAuthenticationSession()方法

登入超時

  • 如果使用者在登入頁,長時間停留(達到了後臺配置的“登入超時”時間),不進行登入提交操作,會出現登入超時,請重新開始登入的提示,這時,頁面自動重新整理,使用者重新提交登入請求即可。
  • 登入超時配置:領域設定---tokens選項,如圖

對於一種開源框架和產品的學習,我們主要還是實踐中去總結它,只有在實踐中才能發現它的問題及那些“不為你知”的功能。

相關文章