keycloak~refresh_token的深度總結
內容大綱
- keycloak關于會話有效期的配置
- refresh_token作用
- refresh_token使用規范
- keycloak開啟refresh_token的限制
- refresh_token時的錯誤匯總
- keycloak中refresh_token的底層邏輯
- session過期時間的清除策略
一 keycloak關于會話有效期的配置
1. session配置說明及推薦配置`
| 參數名稱 | 推薦配置 | 說明 |
|---|---|---|
Access Token Lifespan |
5分鐘(300秒) | access_token的有效期。 |
SSO Session Idle |
7天(604800秒) | 用戶會話的空閑時間。 |
SSO Session Max |
1年(31536000秒) | 用戶會話的最大持續時間。 |
Client Session Idle |
7天(604800秒) | 客戶端會話的空閑時間。 |
Client Session Max |
1年(31536000秒) | 客戶端會話的最大持續時間。 |
Offline Session Idle |
7天(604800秒) | 離線會話的空閑時間(可選)。 |
Offline Session Max |
1年(31536000秒) | 離線會話的最大持續時間(可選)。 |
SSO Session Idle Remember Me |
7天(604800秒) | “記住我”會話的空閑時間(可選)。 |
SSO Session Max Remember Me |
1年(31536000秒) | “記住我”會話的最大持續時間(可選)。 |
2. 會話最后更新時間(這對session idle會產生影響)
- 去登錄頁換取授權碼后,
這個時間會更新 - 刷新token時,
這個時間會更新 - 主動調用
introspect驗證access_token有效性時,這個時間會更新 - 授權碼登錄,code換token時,這個時間不更新
- 使用access_token訪問具體資源時,這個時間不更新
3. code換token時去掉client限制引發的問題
- 當我們通過客戶端a申請授權碼code后,我們使用客戶端b獲取了access_token和refresh_token
- 這時,我們通過refresh_token來刷新token時,是不成功的,會有兩種場景錯誤
- 當你使用客戶端a來刷新token時,會出現
Unmatching clients400錯誤 - 當你使用客戶端b來刷新token時,會出現
Session doesn't have required client400錯誤
- 當你使用客戶端a來刷新token時,會出現
- 所以,否建議把code換token時client_id的限制去掉,這就引發刷新token的問題
二 refresh_token作用
1. 主要作用
refresh_token是用來刷新access_token的,當access_token過期后,可以通過refresh_token來獲取新的access_token,而不需要重新登錄。
2. 動態會話續期規則
- SSO Session Max的限制:
- 無論用戶如何活躍或使用refresh_token,會話的總持續時間不能超過SSO Session Max。
- 例如,如果SSO Session Max設置為1年,即使用戶每天都在使用App,1年后會話也會過期,用戶需要重新登錄。
- SSO Session Idle的限制:
- 如果用戶在SSO Session Idle時間內沒有任何操作,會話將過期,即使用戶使用refresh_token也無法續期。
三 refresh_token使用規范
1. 使用方法
curl --location --request POST 'https://{keycloak}/auth/realms/{realm}/protocol/openid-connect/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=refresh_token' \
--data-urlencode 'refresh_token={refresh_token}' \
--data-urlencode 'client_id={client_id}' \
--data-urlencode 'client_secret={client_secret}'
**2. 使用規范
- 每個refresh_token只能使用一次,不可重復使用,KC這邊也會進行回收它
- 通過refresh_token獲取新的token時,返回值里會帶有
新的refresh_token,我們應該使用新的refresh_token來覆蓋上一次的refresh_token - refresh_token有效期取決于keycloaktokenssso session idle的值,即會話空閑時間,如果refresh_token在這個時間內沒有使用,那么它會失效
- refresh_token失效后,當前會話session_state也即失效,此時,需要重新登錄
注意:
sso session max表示會話最大有效期,在這個時間范圍內,用戶不需要重新登錄,sso session idle表示會話空閑時間,在這個時間內用戶不進行操作,會話也會過期(在下次用戶主動刷新token時,這個會話將會從keycloak后臺會話管理中刪除),session max表示最大會話時間,相當于會話在緩存里的有效期,到期后自動清除(緩存自身的特性,不需要keycloak干預;而離線會話由于是存儲到mysql的,這塊是通過任務調度進行清理的),這兩種情況滿足后,用戶都需要重新登錄,這兩個值必須大于0;單位為分,小時,天,不支持永久有效期。
用戶在刷新token時,如果會話已經失效(session idle到期,而不是session max到期,后者會自動清理),則刪除它(而不是keycloak主動檢查的)

四 keycloak開啟refresh_token的限制

五 refresh_token時的錯誤匯總
-
當refresh_token超過限制時,會返回
invalid_grant錯誤,此時,需要重新登錄

-
再次使用refresh_token,同樣返回狀態碼400,但返回消息體會有變化

-
如果當前session已經失效,即會話達到了session max的時間,將返回下面錯誤

-
如果當前客戶端與token客戶端不一致,將返回下面錯誤

-
如果當前當前端開啟了同意許可,將返回下面錯誤

六 keycloak中refresh_token的底層邏輯
-
validateToken方法

-
通過session_state獲取userSession對象,如果userSession對象為空,說明refresh_token已經失效,返回
400Session not active

-
isSessionValid方法主要驗證會話是否有效,主要判斷以下幾個部分
- 用戶會話是否存在,user-session是否存在
- 獲取session空閑時間和最大時間,它們的邏輯與是否開啟
記住我有關 - 會有兩層時間的比較,來確定session是否有效
- 第一層,session空閑時間是否大于(當前時間-最后刷新token時間-容錯窗口期(120秒))
- 第二層,session最大時間是否大于(當前時間-session開始時間)
- 上面兩層同時滿足,說明session是有效的

- 從userSession中獲取當前用戶對象
- 判斷用戶是否有效
- 如果用戶被刪除,返回
400Unknown user - 如果用戶狀態為禁用,返回
400User disabled - 如果用戶需要一個
必要的行為,返回400User has required action
- 如果用戶被刪除,返回
- 判斷當前refresh_token的建立時間是否早于會話開始時間,正常情況下肯定是晚于會話時間,如果早于,返回
400Refresh toked issued before the user session started - 判斷當前userSession是否在當前client_id對應的clientSession里,如果沒有,返回
400Session doesn't have required client - 判斷當前refresh_token里的azp是否與請求參數
client_id相同,不同返回400Unmatching clients - 驗證refresh_token是否被篡改
- 檢查客戶端是否有consent的授權許可同意,如果開啟了,會返回
400Client no longer has requested consent from user - 成功建立新的token對象,整個刷新token流程結束
{
"access_token": "",
"expires_in": 120,
"refresh_expires_in": 300,
"refresh_token": "",
"token_type": "Bearer",
"id_token": "",
"not-before-policy": 1740449130,
"session_state": "424b8022-600d-421e-a45d-e0315d1a524d",
"scope": "openid roles email profile"
}
七 session過期時間的清除策略
1. 普通會話
- 通過infinispan緩存里的過期時間自動管理,到期后,自動清除
2. 離線會話
- keycloak通過定時器,實現離線會話的清理,它存到mysql中,這是沒有過期時間可言的,可查看offline_user_session相關的內容
- org.keycloak.services.scheduled.ScheduledTaskRunner # 默認900秒(15分鐘)執行一次
- org.keycloak.services.scheduled.ClearExpiredUserSessionsTask
- org.keycloak.models.map.authSession.removeExpired
- org.keycloak.services.scheduled.ClearExpiredUserSessionsTask
浙公網安備 33010602011771號