IdentityServer4【Topic】之登出


Sign-out 登出

IdentityServer的登出就像刪除認證cookie一樣簡單,但是為了完成一個完整的聯合簽名,我們必須考慮將用戶從客戶端應用程序中(甚至可能是上游的Identity提供者)登出。

Removing the authentication cookie刪除認證cookie

簡單的調用HttpContext的SignOutAsync方法就能刪除認證cookie,要使用該方法,你需要傳遞那個使用的認證方案(scheme,默認情況下是IdentityServerConstants.DefaultCookieAuthenticationScheme,除非你更改過它):

await HttpContext.SignOutAsync(IdentityServerConstants.DefaultCookieAuthenticationScheme);

或者你也可以使用IdentityServer提供的這個更為便利的擴展方法:

await HttpContext.SignOutAsync();

通常情況下,應該提示用戶登出(意味着需要一個POST),否則攻擊者可以將其鏈接到您的注銷頁面,從而導致用戶自動注銷。

Notifying clients that the user has signed-out通知客戶端用戶已經登出

作為signout這個整體動作的一部分,應該確保客戶端應用程序也得到了用戶登出的信息,對於有服務端的客戶端,IdentityServer提供了對front-channel規范的支持;對於基於瀏覽器的javascript客戶端(例如SPA、React、Angular等),IdentitySever提供了對 session management 規范的支持。

實際上,OIDC定義了三個規范來完成撤銷認證這個動作:

  1. Session Management :可選。Session管理,用於規范OIDC服務如何管理Session信息。
  2. Front-Channel Logout:可選。基於前端的注銷機制。
  3. Back-Channel Logout:可選。基於后端的注銷機制。

其中Session Management是OIDC服務自身管理會話的機制;Back-Channel Logout則是定義在純后端服務之間的一種注銷機制,應用場景不多,這里也不詳細解釋了。這里重點關注一下Front-Channel Logout這個規范(http://openid.net/specs/openid-connect-frontchannel-1_0.html),它的使用最為廣泛,其工作的具體的流程如下(結合Session Management規范):

(上圖來自:https://www.cnblogs.com/linianhui/p/openid-connect-extension.html)

在上圖中的2和3屬於session management這個規范的一部。其中第2步中,odic的退出登錄的地址是通過Discovery服務中返回的end_session_endpoint字段提供的RP的。其中還有一個check_session_iframe字段則是供純前端的js應用來檢查oidc的登錄狀態用的。

4567這四步則是屬於front-channel logout規范的一部分,OIDC服務的支持情況在Discovery服務中也有對應的字段描述:

4567這一部分中重點有兩個信息:

  1. RP退出登錄的URL地址(這個在RP注冊的時候會提供給OIDC服務);
  2. URL中的sessionid這個參數,這個參數一般是會包含在idtoken中給到OIDC客戶端,或者在認證完成的時候以一個獨立的sessionid的參數給到OIDC客戶端,通常來講都是會直接把它包含在IDToken中以防止被篡改。

Front-channel server-side clients 


在front-channel規范中,為了從帶有服務端的client上登出用戶,identityserver上面的登出頁面必須渲染一個<iframe>來通知client客戶已經登出。希望被通知的客戶端必須設置了FrontChannelLogoutUri 這個配置。IdentityServer跟蹤用戶登入的那個客戶端,並且在IIdentityServerInteractionService (查看詳情)上面提供了一個GetLogoutContextAsync 的API,這個API返回一個LogoutRequest對象,它帶有一個SignOutIFrameUrl屬性,你的登出頁面必須呈現為<iframe>(原文是:This API returns a LogoutRequest object with a SignOutIFrameUrl property that your logged out page must render into an <iframe>.我這個翻譯很拗口,不知道翻譯的對不對,請指正)

Back-channel server-side clients


要通過back-channel規范從服務器端客戶端應用程序中簽出用戶,identityserver中的SignOutIFrameUrl端點將自動觸發服務器到服務器的調用,將簽名的簽出請求傳遞給客戶端。這意味着,即使沒front-channel客戶端,身份服務器中的“注銷”頁面仍然必須呈現如上所述的SignOutIFrameUrl。希望被通知的客戶端必須有BackChannelLogoutUri配置值集。

Browser-based JavaScript clients

考慮到 session management 規范的設計方式,在identityserver中沒有什么特別的東西,需要做的是通知這些客戶已經登出。但是,客戶端必須在check_session_iframe上執行監控,這是由oidc-client JavaScript library.實現的。

Sign-out initiated by a client application客戶端應用發起的登出請求

如果一個登出請求是被客戶端應用發起的,那么客戶端首先會把用戶重定向到end session endpoint。在處理從end session endpoint通過重定向到登出頁面這件事可能需要保持一些臨時的狀態(state)(比如客戶端登出的重定向uri)。這個狀態或許對於登出頁面是有用的,並且state的標志符( the identifier for the state)也通過一個logoutid的參數傳遞給了logout頁面。

 interaction service 上面的GetLogoutContextAsync API可以用來加載這個state。返回的LogoutRequest對象上的ShowSignoutPrompt屬性指示簽出的請求是否已認證過,並且因此它不提示用戶簽出是安全的。

默認情況下這個state是通過logoutid的值作為一個被保護的數據結構來管理的,通過實現IMessageStore<LogoutMessage>並將其注冊到DI,可以在end session endpoint和登出頁面之間對這個值做一些持久化的工作。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM