1. 程式人生 > >IdentityServer4遷移至3.x版本注意問題詳解

IdentityServer4遷移至3.x版本注意問題詳解

前言

之前有一位購買我課程的童鞋利用最新的IdentityServer4版本即對應.NET Core 3.x,釋出到生產環境在學習,結果出了一些問題,此前我並未過多關注IdentityServer4升級到3.x版本,所以在此做一個基本的總結,或許能對出現相同問題的童鞋能提供一點幫助。

IdentityServer4遷移至3.x版本問題

針對將.NET Core 2.x升級到3.x就不用再多講,請參看官方遷移文件(https://docs.microsoft.com/en-us/aspnet/core/migration/22-to-30?view=aspnetcore-3.1&tabs=visual-studio),我們只介紹對於對於配置IdentityServer4方面的更改變化

.NET Core Identity

對於Identity裡面的上下文【IdentityDbContext】需要額外下載包【Microsoft.AspNetCore.Identity.EntityFrameworkCore】

 OIDC配置

 針對如下客戶端OIDC的配置,需要下載包【Microsoft.AspNetCore.Authentication.OpenIdConnect】

授權中介軟體配置 

針對客戶端認證和授權配置,需要如下配置授權中介軟體(認證和授權無先後順序)

遷移類生成

我們知道在此之前對於遷移命名是包含在dotnet CLI裡面,現已修改為通過單獨的包來進行,所以我們需要下載包【Microsoft.EntityFrameworkCore.Design】,否則將丟擲如下異常

還有可能遇到命令列工具版本和當前.NET Core版本不一致的問題,通過如下命令進行更新

  //使用PowerShell或CMD命令更新

  //更新到指定版本
(1)dotnet tool update --global dotnet-ef --version 3.1.2

  //更新到最新版本
(2) dotnet tool update --global dotnet-ef

Cookie安全策略問題(劃重點) 

在本地環境可能麼有任何問題,但是到了生產環境,可能會丟擲如下錯誤,我們是不是會一臉懵逼呢。

warn: Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler[15]
'.AspNetCore.Correlation.oidc.x9I39lxuVXliU0_mOAEPEbZy_EPESHQQRvq7LPatX7rv7y_vQi-HKLIwqNacHM62AeKarJVmr_KvjAL7nSX6hdeR' cookie not found.
info: Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler[4]
Error from RemoteAuthentication: Correlation failed..

這要從Cookie的出生故事說起,大約在20年前設計cookie時以及之後重新設計該cookie時,跨站點請求偽造(CSRF)攻擊和跟蹤使用者都不是什麼大事,在cookie規範中說,如果為特定域設定了cookie,則瀏覽器發出的每個請求都會將其傳送到該域,無論我們是否直接導航到該域,如果瀏覽器只是從該域載入資源(即影象),向其傳送POST請求或將其一部分嵌入到iframe中,但是還有一種情況,我們並不希望瀏覽器自動將使用者會話cookie傳送到伺服器,因為這將允許任何網站會執行指令碼,該指令碼在該使用者的上下文中對伺服器執行請求,為避免這種情況,於2016年起草了SameSite cookie規範,它使我們可以更好地控制何時應傳送和不應該傳送cookie,設定cookie時,我們現在可以在瀏覽器將其新增到其中時為每個cookie明確指定,為此,它引入了當瀏覽器位於我們自己的域上時相同站點cookie的概念,以及當瀏覽器導航到另一個域但將請求傳送到我們的域時跨站點cookie的概念,為了向後相容,相同站點cookie的預設設定並不會更改以前的行為,若我們加入該新功能,需要將cookie顯式設定為SameSite = Lax或SameSite = Strict,以使其更加安全,這已在.NET Framework和所有常見的瀏覽器中實現,Lax表示將在初始導航時將cookie傳送到伺服器,Strict表示僅在我們已經在該域中時(即在初始導航之後傳送第二個請求)才傳送cookie。但是呢,這項新功能卻並沒有被廣泛採用(基於2019年3月Chrome的遙測資料,Chrome在全球範圍內處理的所有cookie中,只有0.1%使用了SameSite標誌,Google為了實現推動該新功能的目標,他們決定更改世界上最常用的瀏覽器的預設設定:Chrome 80將需要新指定的設定SameSite = None來保持處理Cookie的舊方法,並且如果我們像建議的舊規範那樣省略SameSite欄位的話,它將cookie與SameSite = Lax一起設定,請注意:僅當cookie也被標記為Secure並且需要HTTPS連線時,設定SameSite = None才有效,這裡關於更多SameSite的資訊就不再闡述。如果我們有一個單頁Web應用程式(SPA),該Web應用程式通過另一個域上託管的身份提供程式(例如IdentityServer 4中的Idp)進行身份驗證,並且該應用程式使用所謂的令牌重新整理,則將會受到影響,登入IdP時,它將為我們的使用者設定一個會話cookie,並且該cookie來自IdP域,在身份驗證流程結束時,來自不同域的應用程式將收到某種訪問令牌,這些令牌通常生命週期並不長,當該令牌過期時,應用程式將無法再訪問資源伺服器(API),如果使用者每次都必須再次登入,可想使用者體驗之差,為防止這種情況,我們可以使用重新整理令牌,在這種情況下,應用程式將建立一個使用者不可見的iframe,然後在該iframe中再次啟動身份驗證過程, IdP的網站已載入到iframe中,並且如果瀏覽器通過IdP傳送會話cookie,則會識別使用者併發出新令牌,現在,iframe位於應用程式域中託管的SPA中,其內容來自IdP域,這將被視為跨站點請求,因此,如果Cookie明確指出SameSite = None,則Chrome 80只會將該Cookie從iframe傳送到IdP,否則,令牌重新整理將在Chrome 80中出現中斷的情況。也還有其他可能潛在的問題,如果我們在Web應用程式或網站中嵌入了來自另一個域的元素(例如視訊),並且這些元素需要Cookie才能正常執行(例如自動播放設定),那麼這些也會需要設定SameSite策略,如果我們的應用程式需要從瀏覽器請求依賴Cookie身份驗證的第三方API,則同樣適用,我們只能更改自己伺服器從而設定cookie行為。

 

講解了這麼多貌似好像沒有用的廢話,實際上就是出現了跨站點安全策略即SameSite的設定,如上異常的丟擲,追本溯源在於是什麼原因導致了客戶端的Cookie丟失?通過上述對Cookie的講解,我們可以顯式設定SameSite安全策略從而保證到底發不傳送Cookie,所以我猜測在.NET Core 3.x中是不是更改了Cookie的安全策略,如果客戶端的為Strict的話,那就會導致上述異常的發生,比如如下:

說到這裡,為了驗證我的結論,我立馬翻看了關於.NET Core中Cookie對於安全策略的設定,難道真的將Strict作為預設的安全策略嗎?

 

原來該安全策略的預設選項就是Lax(寬鬆策略),然後繼續來到上述的issue(https://github.com/aspnet/Security/issues/1231),在2.0中就解決了此問題將Strict修改為了Lax,就是為了解決OAuth中重定向跳轉認證的問題。這個結果雖在意料之中,但是也在意料之外,那位童鞋也遇到了丟擲上述異常的問題,我就是顯式設定上述安全策略為Lax得到了解決,讓我很是納悶,這是何故,我也不知道,但是確確實實是解決了,最終客戶端也正常跑起來了,真是(捂臉)的表情。最後也同樣重要的是,IdentityServer4在生產環境中是啟用了HTTPS,所以在釋出到生產環境後若未使用HTTPS,一定要將啟用HTTPS選項顯式配置為false,而本地則不然,遇到問題首先分析問題,然後看官方文件,如若還不能解決,只能通過經驗來進行可能原因分析了。

總結

本節我只是將IdentityServer4升級到.NET Core 3.x的版本需要注意的問題做了一個粗略的解答,根據我的經驗,一部分原因出在對於官方文件概念未詳細解導致,另外一部分原因出在由於版本升級導致內建處理出現了更改,但官方文件並未更新,這個最麻煩,出現這樣的問題只能硬啃原始碼並除錯,我也同時將我原先在長沙社群成立時所演講的IDS4 Demo已更新到了最新.NET Core 3.1.2版本(https://github.com/wangpengxpy/IdentityServer4Sample