在上一篇文章中我們介紹了單頁應用是如何使用IdentityServer完成身份驗證的,并且在講到靜默登錄以及會話監聽的時候都提到會話(Session)這一概念,會話指的是用戶與系統之間互動程序,反過來說就是用戶與系統之間互動的狀態就保存在會話(Session)中,對于HTTP協議來說,由于它本身是無狀態的,所以為了能夠記錄用戶訪問系統的狀態,一般使用Cookie來存放會話資訊,但是現在我們需要保存的是與IdentityServer之間的會話,對于單頁應用來說它一般會存在跨域問題,那IdentityServer是如何處理跨域來完成會話管理的呢?同時IdentityServer4又提供了哪些與登錄登出相關的特性?本文就從會話管理開始來一一介紹, 本文內容有:
- 會話管理
- 前端登出
- 授權服務器(OP)登出聯動客戶端(RP)
- 原理決議
- 客戶端(RP)登出聯動授權服務器(OP)
- 后端登出
- 小結
會話管理
首先會話本身有兩個主體,即服務器和客戶端,服務端就是identityServer本身,它是一個asp.net core應用程式,那么實際上它的會話機制就和普通的asp.net core應用程式是一致的,通過cookie來保存相應會話的id或資訊, 下圖為登錄IdentityServer后瀏覽器端存盤的會話資訊和身份資訊:
- 協議定義:如何持續監控終端用戶在OpenID Provider(OP,Identity Server)上提供的會話資訊,以便于終端用戶登出OpenID Provider(OP,IdentityServer)時能夠同時登出客戶端(Relying Party),
- iframe:一個HTML的標簽,它代表一個內嵌的HTML檔案,如果在HTML使用iframe那就是檔案中包含另一個檔案,iframe可以通過src屬性來設定包含檔案的url地址,當iframe設定的url與主檔案的url不同域時,可以使用iframe的postmessage方法實作跨域通信,
- RP iframe:位于客戶端(Relying Party, RP)中的一個iframe,這個iframe的作用是用于向OP iframe發送及接收資訊,發送的資訊是用于告知OP iframe進行會話檢查,接收的資訊是OP iframe完成會話檢查后的結果,
- OP iframe:一個由OpenID Provider(OP,IdentityServer)提供的,位于客戶端(Relying Party, RP)中的一個iframe,它的作用是與IdentityServer同域,保存于IdentityServer的會話資訊,并提供檢查介面(基于postmessage)的iframe,
圖中存在兩個iframe,第一個是OP iframe包含了會話檢查相關內容,第二個是發起靜默登錄時,創建的一個指向授權終結點的iframe,通過跨域完成登錄,需要注意的是由于RP iframe是通過js代碼創建的,所以無法在頁面代碼中找到,
前端登出
OIDC前端登出協議(OpenID Connect Front-Channel Logout),這個協議提供了一種登出的機制,該機制是通過瀏覽器的前端技術來與被登出的客戶端(RP)/服務器(OP)建立通信,不再需要iframe就可以實作相關登出功能,具體協議內容參見:https://openid.net/specs/openid-connect-frontchannel-1_0.html 接下來我們就通過asp.net core應用程式來演示一下這個協議是如何完成前端登出的,授權服務器(OP)登出聯動客戶端(RP)
1. API專案中添加一個登出頁面 API專案實際上就是我們的客戶端(RP),當前的例子就是通過在該應用上添加一個登出頁面來完成授權服務器登出后通知客戶端登出的功能, 注:asp.net core api專案實際上是不包含頁面的,此處僅為了方便通過api專案中添加Razor頁面來完成演示, 首先添加一個Razor頁面的布局:

原理簡析
它們是如何完成聯動登出的呢?我們首先來分析一下相關主體有哪些:- 客戶端(RP)登出頁面:訪問該頁面即可完成客戶端(RP)方面的登出,這個頁面用于授權服務器登出聯動時訪問,
- 授權服務器(OP)登出頁面:一個基于Asp.net core Identity的登出頁面,用于asp.net core應用程式(這里特指授權服務器)的登出,
- 授權服務器(OP)前端登出頁面:一個用于完成OIDC前端登出協議的登出頁面,負責客戶端登出頁面的呼叫及客戶端應用程式跳轉(該頁面功能有點類似于,我們在購買火車票付款時,首先跳轉到支付頁面,完成支付后通知系統已支付,并且又跳轉回訂單頁面的程序),
- IdentityServer4的互動服務(Interaction Service):這個實際上就是identityServer4提供的一組介面,這些介面約定了用戶與IdentityServer4的互動方法,該介面可以通過依賴注入的方式進行使用,在本例中使用Interaction Service的目的是獲取當前登錄用戶的登出背景關系,以便完成后續登出作業(相關資訊存盤于Cookie中,類似基于Cookie身份驗證的身份資訊載體),關于介面內容詳見檔案:https://identityserver4.readthedocs.io/en/latest/reference/interactionservice.html
- 結束會話終結點(End Session Endpoint):就是字面意思,結束會話使用的終結點,在這里的作用是通過結束會話終結點來終結會話并跳轉到客戶端(RP)的登出頁面完成客戶端(RP)登出,
客戶端(RP)登出聯動授權服務器(OP)
以上面所提到的三個要點來看如何實作客戶端(RP)與授權服務器(OP)的登出聯動, 首先我們在客戶端添(RP)加一個登出頁面:
后端登出
前面提到的無論是會話管理還是前端登出,它都有一個共同點就是基于瀏覽器,因為瀏覽器可以通過Cookie或者H5的存盤功能來保存會話/狀態資訊,登出實際上就是把相應的資訊洗掉,這種情況下不管是客戶端(RP)還是授權服務器(OP)它們本身都只是去驗證身份資訊的有效性,如果身份資訊存在且有效那么身份驗證通過,但是實際應用中可能會出現這么一種情況,假設身份資訊過期時間足夠長,那么只要用戶不主動登出,那么身份資訊將永久保存、永久有效,服務端沒有“任何”一種方法能夠主動讓其失效,這是存在問題的,針對這種問題OIDC提出了后端登出這一概念, 后端登出是什么呢?它實際上是一種授權服務器(OP)與客戶端(RP)之間直接通信的登出機制,簡單說來就是當通過授權服務器(OP)登出時可以直接通知到客戶端(RP),不需要瀏覽器的支持,說個具體場景就類似于微信可以同時在PC以及移動設備上登錄,但是移動設備上可以直接控制PC登出,或者是當用戶修改密碼后,密碼修改前所有的會話都應被終止, 后端登出雖然不再基于瀏覽器的會話資訊,但是它畢竟需要明確知道相關登出的會話資訊,所以它本身比前端登出要復雜,需要授權服務器(OP)以及客戶端(RP)都支持會話管理,對于授權服務器來說可以通過訪問https://localhost:5001/.well-known/openid-configuration來確定是否支持后端登出:
關于如何獲取會話資訊來通過該服務發起登出會在后續文章中介紹,
小結
本文主要介紹了IdentityServer4的會話管理以及前后端登出功能,其中會話管理和前端登出都是基于瀏覽器,通過瀏覽器本身的Cookie及存盤功能來保存相關身份、會話資料,同時借助Iframe來實作跨域請求、跨域會話檢查等等功能, 對于前端登出來說它主要有授權服務器(OP)與客戶端(RP)互相聯動兩種場景,無論用戶從哪一方進行登出操作都能夠將兩方的身份資訊洗掉, 對于后端登出來說它要求授權服務器(OP)與客戶端(RP)雙方都具備后端登出功能,IdentityServer4本身支持,而客戶端就需要自己實作了,本文中實作了一個簡單的登出會話管理功能,即當用戶觸發后端登出后,客戶端會記錄登出資訊,當用戶再次發起請求時,在身份驗證(驗證Cookie,此時Cookie仍然有效)后,來判斷該用戶是否已經后端登出,如果已經登出則主動拒絕訪問, PS. 這篇文章寫的時間跨度有點大,文章內容相對較多,并且有大量的檔案和代碼修改,但文中代碼均已圖片形式展現,本系列文章完結后會上傳相關代碼檔案,如有問題可隨時聯系作者, 參考: https://stackoverflow.com/questions/10663873/user-identity-isauthenticated-true-after-logout-asp-net-mvc https://www.codeproject.com/tips/1115491/request-isauthenticated-is-always-true-after-call https://openid.net/specs/openid-connect-session-1_0.html https://openid.net/developers/specs/ https://identityserver4.readthedocs.io/en/latest/reference/interactionservice.html https://openid.net/specs/openid-connect-rpinitiated-1_0.html https://github.com/IdentityServer/IdentityServer4/tree/main/samples/Clients/src/MvcHybridBackChannel 本文鏈接:https://www.cnblogs.com/selimsong/p/14630356.html 從零搭建一個IdentityServer——目錄(更新中...)轉載請註明出處,本文鏈接:https://www.uj5u.com/net/273950.html
標籤:.NET Core
