基於REACT和.NET CORE整合WINDOWS身份驗證
有很多方法可以向您的應用程式新增身份驗證。雖然OAuth是最常見的一種,但這並不是您唯一的選擇。今天,我將向您展示如何通過React和.NET Core簡單地完成Windows身份驗證。
探索我們的選擇
在深入探討之前,讓我們簡要討論一些可用的其他選項。瞭解您的選擇,可以使您根據自己的情況做出最佳(受過良好教育)的決定。這絕不是關於替代方案的詳盡討論,而只是其中一些較流行的替代方案。
Okta 是一家身份和訪問管理公司,提供基於雲的解決方案。他們有 Active Directory 的 外掛/提供程式 。他們的站點包含一個教程,如何 開始向 您的React應用程式 新增身份驗證 。在商業解決方案方面,該解決方案經常被推薦使用。
Auth0 是另一個具有良好關注度的商業解決方案。他們有專門針對將 Active Directory / LDAP與React結合 使用的教程。
IdentityServer 是開源替代方案。就像其他人一樣,他們提供了有關 如何實施Windows身份驗證的說明 。他們有一個有關 如何實現javascript客戶端 (例如React)的示例。這是有關 在Identity Server 4中使用SPA(反應/角度)UI的文章 。
當然,我們今天在這裡討論的選擇是推出您自己的解決方案。
為什麼不選擇交鑰匙解決方案?
儘管您的原因可能有所不同,但我想出了一些原因。
-
基礎結構/資源不足,無法設定服務(適用於Identity Server 4)。
-
資金/預算不足,無法支付SAAS提供商的費用。
-
您位於防火牆之內,並且React和.NET應用程式都位於同一網路上。
-
您喜歡挑戰和/或喜歡重新發明輪子(哈!)
好的,也許最後一個有點有趣。一般來說,使用交鑰匙解決方案 是 最好的選擇,但不是 您的 選擇。在我遇到的這個特殊用例中,這不是我想要的。然而。
入門
為了構建此應用程式,我們需要兩件事:
-
.NET Core API專案–該專案將處理身份驗證,授權以及API呼叫
-
React應用程式–該專案是我們的GUI
我為該專案學習和應用的東西是Google-fu精通和反覆試驗編碼的結合。希望彙總我的經驗將使您(我的讀者)比我更容易。
我首先建立一個資料夾來包含我的API和React專案,然後執行 dotnet new api -o ReactWindowsAuth
以搭建一個新的API專案。(這實際上是一個謊言,我使用VS來建立應用程式,但是我們假裝使用了CLI)。從那裡開始,我執行 npm create-react-app test-app
了一個名為的基本React應用程式 test-app
。就個人而言,我喜歡將Visual Studio用於.NET程式碼,將VSCode用於幾乎所有其他內容,因此我在VS中打開了新的API專案並生成了解決方案檔案。
從這裡開始,我們現在可以開始使用React和.NET Core實施Windows身份驗證了!
框架.NET Core API
我們需要做的第一件事就是確保我們的應用程式以Windows身份驗證執行。由於我使用VS生成了專案並提供了Docker支援,因此我不得不做一些您可能不需要做的事情。
啟用Windows身份驗證
我要做的第一件事是將除錯啟動器從Docker切換到IIS Express。
切換預設啟動
接下來,我需要開啟我的 launchSettings.json
並 "windowsAuthentication": true
在 iisSettings
下進行設定。
啟用Windows身份驗證
好吧,讓我們稍等一秒鐘。為了使Windows身份驗證起作用,您將需要在IIS或IIS Express中進行託管。您也可以使用 Kestrel 和 HTTP.sys 託管來完成此操作,但出於本文的方便,讓我們集中討論IIS Express。如果您想使它在Docker和/或Linux上執行,您將要使用Kestrel。
我們的應用程式現在可以與Windows身份驗證一起使用了,但是如果我們現在啟動它,它仍然不會使用。我們還有很多工作要做。
配置Windows身份驗證
現在我們已經設定了API以通過IIS使用Windows身份驗證,我們需要使API本身意識到這一點。為此,我們需要對進行一些調整 Startup.cs
。 MSDN上有文件 ,但我們也可以在這裡進行閱讀。
您需要做的第一件事是 services.AddAuthentication(IISDefaults.AuthenticationScheme);
在您的 ConfigureServices
方法中新增任何位置。這利用了 Microsoft.AspNetCore.Server.IISIntegration
名稱空間。
新增Windows身份驗證
接下來,您需要配置Windows身份驗證需要保護哪些控制器或動作。順便說一下,這就是為什麼我們 "anonymousAuthentication": true
獨自留在 launchSettings.json
。這裡的一個用例是,如果您使用的是Swagger,並且希望匿名訪問文件並且僅保護API本身。
在我的用例中,我假裝我希望所有API控制器都需要身份驗證。鑑於此,我建立了一個 WebControllerBase.cs
,並用 [Authorize]
屬性對其進行了裝飾。請注意,您可以改為用[Authorize]標記每個控制器。就是說,我的理由實際上是押韻的,在以後的第二部分中,我將進一步闡述這個想法。現在,只需滾動即可。
WebControllerBase,將[Authorize]標記為需要身份驗證
接下來,只需讓我們現有的控制器和新控制器繼承自 WebControllerBase
而不是即可 ControllerBase
。
現在,我們現有的控制器繼承自WebControllerBase
在網路上的其他示例中,您可能會看到人們說您需要新增 app.UseAuthentication()
該 Configure(IApplicationBuilder app, IWebHostEnvironment env)
方法。如果僅針對IIS / IIS Express,則不會。也就是說,新增它不會傷害您。我不會判斷你是否願意。我的原始碼有它。
測試一下!
現在,我們可以對其進行測試了。在WeatherForecastController頂部打一個斷點:以除錯模式獲取並執行Web應用程式。達到斷點時,新增監視 HttpContext.User
並向下鑽取 .Identity.Name
。(可選)只需在方法頂部新增此行: var user = HttpContext.User?.Identity?.Name ?? "N/A";
並檢視結果。您的應用程式現在正在報告您當前的Windows使用者名稱,對嗎?
哇,等等,您還沒有完成!
我們已經接近了,但是如果我們想在React中使用它,我們還有很多工作要做。CORS。別說了。什麼是CORS? CORS是跨域資源共享 ,這是您要允許[this]訪問[that]的一種非常真實的方式。在現實世界中,預設情況下將瀏覽器配置為禁止通過指令碼發起的HTTP請求,除非接收端明確允許。
所以……讓我們做一下,這樣這個API可以接受來自React應用程式的CORS請求,對吧?我們不會在這裡變得很花哨。為了使此操作生效,我們需要在中新增一些設定, appsettings.json
然後在中進行其他設定 Startup.cs
。
appsettings.json
首先,我們去 appsettings.json
新增以下內容: "CorsOrigins": [ "http://localhost:3000" ],
。是的,它是陣列型別。為什麼?主要是因為它為您提供了選擇。假設在開發中,我打開了通往機器的通道,以便某人(甚至我)可以從另一臺裝置訪問該應用程式。顯然,它們不會通過本地主機名或IP地址連線到localhost。所有這些都是我可能要設定的選項。
啟動檔案
接下來,我們需要 將CORS新增 到我們的服務和中介軟體中。在ConfigureServices中,請新增以下程式碼:
// add this class somewhere outside of the Startup class public class Constants { public const string CORS_ORIGINS = "CorsOrigins"; } services.AddCors(opt => { opt.AddPolicy("CorsPolicy", builder => builder .AllowAnyHeader() .AllowAnyMethod() .WithOrigins(Configuration.GetSection(Constants.CORS_ORIGINS).Get<string[]>()) .AllowCredentials()); });
此程式碼的簡要說明。它允許傳遞任何標頭,使用任何http方法(GET,POST,PUT,DELETE等),必須來自配置中特定的來源之一,並允許在標頭中傳遞憑據。在您自己的應用程式中,您可以更改許多設定。您可能不會更改其中任何一個。至少您現在知道它們了。
接下來,我們需要新增 app.UseCors("CorsPolicy")
到我們的 Configure(app, env)
方法中。請注意,這是中介軟體和 中介軟體順序 。在這種情況下,它需要跟從 app.UseRouting()
但在此之前 app.UseAuthentication()
和 app.UseAuthorization()
。順便說一句,如果您添加了中介軟體,但中介軟體工作不正常,則應檢查其註冊順序。
現在使用app.UseCors(“ CorsPolicy”)配置方法
現在我們準備好讓我們的React應用程式與Windows身份驗證掛鉤了!
帶有React的Windows身份驗證–連線起來!
對此感到興奮嗎?我知道我是。這比您想象的要容易。準備好了嗎?
您需要做的就是在 fetch
請求中新增兩個屬性: credentials: "include"
和 mode: 'cors'
。
將會發生的情況是,如果您訪問的站點與您不在同一域(或計算機)上,則瀏覽器將提示您輸入該Active Directory,LDAP或計算機例項的憑據。成功進行身份驗證後,瀏覽器將其儲存以備將來使用。如果您在完全相同的計算機或域上,則不會提示憑據。
話雖如此,您可以(並且可能應該)設定服務f呼叫的方式,因此不必在各處都輸入相同的垃圾。當我第一次開始使用React時,我很快意識到,設定一些獲取幫助程式來啟動它比較容易。我意識到的第二件事是,在React程式碼中將所有.NET API控制器與“服務”進行匹配更加容易。
考慮到這一點,讓我們看一下我的提取幫助器和示例服務。
fetch-helpers.js
這是我在此測試應用程式中擁有的一些基礎知識:
export const handleResponse = (response) => { return response.text().then((text) => { const data = text && JSON.parse(text); if (!response.ok) { const error = (data && data) || response.statusText; return Promise.reject(error); } return data; }); }; export const requestBase = (() => { if (typeof window !== "undefined") { return { method: "POST", credentials: "include", mode: 'cors', headers: new Headers({ Accept: "application/json", "Content-Type": "application/json", }), }; } else return { method: "POST", credentials: "include", // mode: 'cors', headers: { Accept: "application/json", "Content-Type": "application/json", }, }; })();
值得注意的是, requestBase
如果它不是NodeJS(經過渲染的React),則可以具有不同的返回物件。很難發現差異,但是無瀏覽器版本將標頭設定為Headers物件的例項,而瀏覽器版本僅設定JSON物件。
weather-api.js
接下來,讓我們看看我們的服務如何使用fetch-helpers。首先,下面的apiBase是完整的URL。顯然,您不會這樣做,但實際上會將React的baseUrl設定為更高的級別(通常在HTML級別)。這是示例程式碼,請加一點鹽。
import { handleResponse, requestBase } from "../_helpers"; const apiBase = "http://localhost:44387/weatherforecast"; class WeatherForecastService { getForecasts() { let request = Object.assign({}, requestBase, { method: "GET" }); let url = `${apiBase}`; return fetch(url, request).then(handleResponse); } getProtectedForecast() { let request = Object.assign({}, requestBase, { method: "GET" }); let url = `${apiBase}/5`; return fetch(url, request).then(handleResponse); } } const instance = Object.freeze(new WeatherForecastService()); export { instance as WeatherForecastService };
我在這裡所做的只是公開我希望React可以訪問的方法,將它們包裝在 baseRequest
from的周圍,並 fetch-helpers
使用我的 handleResponse
from 來處理響應 fetch-helpers
,然後傳遞迴呼叫方。
最後但同樣重要的是,將其連線起來!
現在我們已經鋪設了所有管道,現在該連線所有東西了。我只是直接編輯App.js。告我。對於該示例,我將匯入所有三個API服務檔案,然後 const
為我要處理的每個按鈕設定一些功能。其中的每一個都僅登出到控制檯,而不用花費大量精力。最後,當然是按鈕本身。由於該檔案在修改後相當龐大,因此我僅摘錄了按鈕事件之一以及呼叫它的React按鈕元件本身。
const getProtectedForecast = () => { console.log("attempting..."); WeatherForecastService.getProtectedForecast() .then((response) => { console.log("response: ", JSON.stringify(response)); console.log("oh boy!"); }) .catch((err) => { console.error(err); }); }; <button type="button" onClick={getProtectedForecast}> Get protected forecast </button>
重要環節– Windows身份驗證基於角色的安全性
雖然上述設定是非常基本的,但它缺少一個非常重要的部分,不是嗎?基於角色的安全性。在這裡考慮一下此內容,這是對第2部分的非常簡短的介紹,而我將在不久的將來寫一篇文章。如果你已經點選周圍的程式碼,而閱讀這篇文章,你可能已經注意到在Startup.cs以下行:ConfigureServices: services.AddTransient();
。如果您沒有注意到它,那是可以的,因為我現在將談論它。
在對使用者進行身份驗證之後但在獲得授權之前,授權提供者將呼叫您的自定義 IClaimsTransformation
實現(如果提供)。 參見MSDN 。在我的實現中(位於中 ClaimsTransformer
),您將看到我只是在隨意新增角色“ Super-awesome”作為我們 WindowsIdentity
用於其宣告型別的相同宣告型別。
IClaimsTransformation的ClaimsTransformer實現者
接下來,您可能已經注意到 WeatherForecastController
我添加了一個 GetAnother
方法呼叫,該方法呼叫需要“超級棒”角色。在此之下,我還添加了一種 GetFail
方法,該方法將始終失敗,因為使用者不在“管理員”角色中。這些方法都沒有連線到React應用程式中,並且要求您直接在瀏覽器中單擊它們以檢視它們是否有效(或可能無效)。
基於Controller動作的基於角色的Windows身份驗證
結論
將Windows身份驗證連線到您的React應用程式並不困難。這也是非常基本的。交鑰匙解決方案可以使您走得更快,更遠,但是如果您沒有基礎設施或現金,仍然可以自己動手做。和往常一樣,我部落格文章中的程式碼可以在 GitHub 上 找到 。
- .NET基礎知識快速通關(9)
- .NET基礎知識快速通關(6)
- .NET基礎知識快速通關(5)
- 面試寶典之.NET基礎知識快速通關(1)
- 填坑 | .NET 在Docker中訪問MSSQL報錯
- 如何分析.NET Core HttpClient請求異常
- 理解C#泛型原理
- 萬字長文講解:什麼是「抽象」?
- 簡述使用REST API 的最佳實踐
- 如何基於.NET Core構建分散式檔案儲存系統?
- 利用SOS擴充套件庫進入高階.NET6程式的除錯
- 淺議開發者面臨的資訊偏差影響因素
- 【新書速遞】龍芯開源LoongArch版,學會造計算機!
- .NET誕生20週年 .NET 7有什麼新東西?
- 基於.NET 製作一個氣象站 IoT 應用
- [探索 .NET 6]02 比較 WebApplicationBuilder 和 Host
- [探索 .NET 6]01 揭開 ConfigurationManager 的面紗
- 基於REACT和.NET CORE整合WINDOWS身份驗證
- 驚爆:Alexa 全球排名網站即將關閉
- 面試必備之C#10語法特性總結