keycloak~token配置相關說明
會話有效期
在 Keycloak 中,"SSO Session Idle" 和 "SSO Session Max" 是用于配置單點登錄(SSO)會話的兩個參數。這兩個參數影響用戶在系統中的會話過期和最大有效時間。
-
SSO Session Idle(單點登錄會話空閑時間):
-
定義: 表示用戶在系統中沒有活動的時間閾值。如果用戶在這段時間內沒有與系統進行交互,那么他們的單點登錄會話就被視為處于空閑狀態。
-
實際意義: 當用戶登錄后,在一段時間內沒有進行任何操作,系統會認為用戶不再活躍,這時候可以選擇在一定的時間后自動注銷用戶,以提高安全性。例如,設置為 30 分鐘,如果用戶在 30 分鐘內沒有任何操作,他們的會話將被認為是空閑的,可以選擇要求用戶重新驗證身份。
-
-
SSO Session Max(單點登錄會話最大時間):
-
定義: 表示用戶單點登錄會話的最大有效時間。即使用戶一直在系統中活躍,當達到此時間閾值后,他們的會話也會被強制注銷。
-
實際意義: 即使用戶一直在系統中活躍,為了安全和資源管理的目的,可以設置一個最大時間,超過這個時間后,用戶將被強制重新登錄,以確保他們的身份驗證狀態是最新的。例如,設置為 8 小時,用戶的會話將在 8 小時后過期,需要重新登錄。
-
這兩個參數通常與安全性和用戶體驗的平衡相關。設置得太短可能導致用戶頻繁需要重新登錄,而設置得太長可能增加安全風險。具體的設置應該根據你的應用程序的安全需求和用戶行為來確定。
Client Session有效期
"Client Session Idle" 和 "Client Session Max" 是 Keycloak 中用于配置客戶端會話的兩個參數。這兩個參數影響與客戶端相關的會話過期和最大有效時間。
-
Client Session Idle(客戶端會話空閑時間):
-
定義: 表示用戶與特定客戶端之間沒有活動的時間閾值。如果用戶在這段時間內沒有與特定客戶端進行交互,那么與該客戶端關聯的會話就被視為處于空閑狀態。
-
實際意義: 當用戶與特定客戶端建立了會話后,在一段時間內沒有與該客戶端進行任何操作,系統會認為用戶與該客戶端的會話是空閑的。這可以用于自動注銷與客戶端的會話,以提高安全性。
-
-
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)相關的設置參數。它們的作用和關系如下:
-
Offline Session Idle(領域設置):這是Keycloak的領域設置中的一個參數,用于定義空閑會話的超時時間。當用戶在一段時間內沒有與Keycloak進行任何交互時,會話會被視為處于空閑狀態。默認情況下,該參數設置為30天。
-
Offline Session Max Limited(領域設置):這是Keycloak的領域設置中的一個參數,用于定義空閑會話的最大持續時間。該參數定義了會話的最長持續時間,從會話開始到會話終止的時間段,以秒為單位。超過這個時間段后,會話將被標記為過期,并將被銷毀。默認情況下,該參數也設置為30天。
-
Offline Session Max(領域設置):這是Keycloak的客戶端設置中的一個參數,用于定義特定客戶端的空閑會話的最大持續時間。每個客戶端可以具有自己的空閑會話最大持續時間,以使具有不同需求的客戶端具有不同的會話時間。默認情況下,它繼承自領域的 "Offline Session Max Limited" 值。
-
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(最大過期時間)不相等時,產生的問題
- session idle會作為刷新token的過期時間
- 當這個時間到達后,不能再刷新token了,但是,session還是在線的
- 是否需要在到達這個時間后,將會話刪除?
- 如果真要刪除的話,可能產生的問題就是session max的時間還沒到,但是session已經被刪除了,這樣就會導致session max的時間不準確了
- 但如果session idle到達,并且token沒有成功刷新,這說明用戶空閑了,這時session是可以刪除的,與4不矛盾
- 解決方法
*[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的時間)來清除的
- org.keycloak.services.scheduled.ClearExpiredUserSessionsTask
通過上面的分析,直接從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選項,如圖

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