keycloak~關于跨域的iframe對接keycloak的分析
幾個cookie下面元素
- AUTH_SESSION_ID 會話級的session_state
- AUTH_SESSION_ID_LEGACY 在http中可見的AUTH_SESSION_ID
- KEYCLOAK_SESSION 帶有效期的session_state
- KEYCLOAK_SESSION_LEGACY 在http中可見的KEYCLOAK_SESSION
- KEYCLOAK_IDENTITY 用戶完成認證后,在cookie記錄用戶和session_state的jwt token
- KEYCLOAK_IDENTITY_LEGACY 在http中可見的KEYCLOAK_IDENTITY
不同頂級域名對接keycloak后auth_session_id被cookie Partition隔離

登錄的過程
以社區登錄為例,對接社區如微信登錄后,在keycloak登錄頁點微信按鈕,
- 登錄頁面 /auth/realms/demo/protocol/openid-connect/auth
- 驗證參數,完成到社區網站的302跳轉 /auth/realms/{realm}/broker/weixin/login?client_id=democlient&tab_id=rzukcX7mOfQ&session_code=OPsAHAZ3HZISaxklQLmcVYJThVUwLh5Y8TkAi5GQPjY
- 在社區網站上完成登錄,由社區302跳轉回keycloak頁面
- 如果社區帳號沒有綁定keycloak用戶,進入first-broker-login頁面,完成用戶的綁定 /auth/realms/demo/login-actions/first-broker-login?client_id=democlient&tab_id=JCCx2WFmFFA
- 在first-broker-login填寫信息提交后,完成綁定,302到post-broker-login頁面 /auth/realms/demo/login-actions/post-broker-login?client_id=democlient&tab_id=dBh9Jl7qib4
- post-broker-login流程處理完成后,302到after-post-broker-login頁面,/auth/realms/demo/broker/after-post-broker-login?session_code=QM5PnTZihZqnVsyCilwJhxLY5viLoCgckPLHF_NkBuA&client_id=democlient&tab_id=dBh9Jl7qib4
- 這樣就完成了keycloak的登錄,然后302跳轉到redirect_uri頁面,登錄結束
跨域iframe登錄出現問題的點
- 打開登錄頁后,生成auth_session_id這個鍵,并添加了當前域名的頂級域名做為cookie的
Partition Key - 點擊社區登錄后,kc服務端進入如下方法
- org.keycloak.services.resources.IdentityBrokerService.performLogin()
- org.keycloak.services.resources.IdentityBrokerService.parseSessionCode()
- org.keycloak.services.resources.SessionCodeChecks.initialVerify()
- org.keycloak.services.resources.IdentityBrokerService.parseSessionCode()
- 經過sessionCode初始檢查之后,在執行到parseSessionCode()方法中代碼AuthenticationSessionModel authSession = checks.getAuthenticationSession();時,authSession的結果為空,故出現無法登錄異常,如下代碼
ERROR [org.keycloak.services.resources.IdentityBrokerService] (default task-1708) unexpectedErrorHandlingRequestMessage: javax.ws.rs.WebApplicationException: HTTP 400 Bad Request
at org.keycloak.keycloak-services@14.0.0//org.keycloak.services.resources.IdentityBrokerService.parseSessionCode(IdentityBrokerService.java:1225)
at org.keycloak.keycloak-services@14.0.0//org.keycloak.services.resources.IdentityBrokerService.performLogin(IdentityBrokerService.java:419)
跨域后的異常
-
有同域的auth_session_id的情況下(已在cookie partitioned為空的網站登錄,與kc認證服務同一頂級域名),在跨域頁面登錄,請求是http 302跳到新登錄頁,顯示登錄超時(或者強制跳到已登錄頁面),原因是kc服務端獲取的auth_session_id與當前頁面傳遞的tab_id和session_code不匹配

-
在沒有其它auth_session_id的情況下,在跨域頁面登錄,顯示錯誤頁,http 400錯誤,原因是kc服務端在無法獲取cookie中帶分區的auth_session_id

-
keycloak使用了會話保持功能,我們使用更穩定的ingress在瀏覽器添加cookie的方式,當在社區超鏈登錄時,它的a標簽里target屬性為_parent或者_top,這樣鏈接發送的cookie是cookie partitioned為空的網站route(狀態保持自動生成),這時會出現請求的kc節點與提交的kc節點不同的情況,也會出現400的錯誤
解決iframe跨域問題的關鍵
- 表單提交登錄,可以適應跨頂域的情況
- 社區a標簽超鏈登錄,如果target=_self,也可以適應跨頂域的情況,其它target屬性,不適合
- 建議統一登錄不使用iframe進行嵌入
浙公網安備 33010602011771號