.NET混合開發解決方案14 WebView2的基本身份驗證

張傳寧發表於2022-05-12

WebView2控制元件應用詳解系列部落格

.NET桌面程式整合Web網頁開發的十種解決方案

.NET混合開發解決方案1 WebView2簡介

.NET混合開發解決方案2 WebView2與Edge瀏覽器的區別

.NET混合開發解決方案3 WebView2的程式模型

.NET混合開發解決方案4 WebView2的執行緒模型

.NET混合開發解決方案5 WebView2執行時與分發應用

.NET混合開發解決方案7 WinForm程式中通過NuGet管理器引用整合WebView2控制元件

.NET混合開發解決方案8 WinForm程式中通過設定固定版本執行時的BrowserExecutableFolder屬性整合WebView2控制元件

.NET混合開發解決方案9 WebView2控制元件的導航事件

.NET混合開發解決方案10 WebView2控制元件呼叫網頁JS方法

.NET混合開發解決方案11 網頁JS呼叫C#方法

.NET混合開發解決方案12 網頁JS呼叫C#方法訪問WinForm或WPF窗體

.NET混合開發解決方案13 自定義WebView2中的上下文選單

  WebView2 應用的基本身份驗證包括從 HTTP 伺服器檢索網頁的一系列身份驗證和導航步驟。 WebView2 控制元件充當主機應用和 HTTP 伺服器之間通訊的中介。

友情提醒:使用基本身份驗證時必須使用 HTTPS。 否則,使用者名稱和密碼不加密。 您可能需要考慮其他形式的身份驗證。 基本身份驗證的 HTTP 標準包括未加密 (使用者名稱和密碼) 憑據。 因此,必須使用 HTTPS以確保憑據已加密。

導航事件的順序

基本身份驗證事件在事件序列的中間發生:

  1. NavigationStarting - 導航事件
  2. ContentLoading - 導航事件
  3. BasicAuthenticationRequested
  4. DOMContentLoaded
  5. NavigationCompleted - 導航事件
HTTP 伺服器、WebView2 控制元件和主機應用之間的通訊
  • HTTP 伺服器檢查身份驗證 (使用者名稱和密碼憑據) 並返回錯誤文件或請求的網頁。

  • WebView2 控制元件例項引發事件。 WebView2 控制元件位於 HTTP 伺服器和主機應用之間。 WebView2 控制元件充當主機應用和 HTTP 伺服器之間通訊的中介。

  • 編寫主機應用。 主機應用在響應物件中設定事件引數 () EventArgs 密碼。

BasicAuthenticationRequestedEventArgs 具有 屬性 Response 。 屬性 Response 是包含使用者名稱和密碼屬性的物件。

導航事件流程

下圖顯示了 WebView2 應用的基本身份驗證的導航事件流:

  1. 主機應用指示 WebView2 控制元件導航到 URI。

  2. WebView2 控制元件與 HTTP 伺服器通訊,請求獲取位於指定 URI 的文件。

  3. HTTP 伺服器答覆 WebView2 控制元件,指出"未經身份驗證 (無法獲取) URI"。

  4. WebView2 控制元件指示主機應用"需要身份驗證" (BasicAuthenticationRequested事件) 。

  5. 主機應用通過向 WebView2 控制元件提供使用者名稱和密碼來響應該事件。

  6. WebView2 控制元件再次從 HTTP 伺服器請求 URI,但這次使用的是身份驗證 (使用者名稱和密碼) 。

  7. HTTP 伺服器對使用者名稱和密碼 (憑據) 進行評估。

  8. HTTP 伺服器可能會拒絕憑據並請求新的憑據。

  9. HTTP 伺服器可能會拒絕使用者名稱和密碼;它可能會告訴 WebView2 控制元件"不允許獲取該 URI/文件"。

  10. WebView2 控制元件呈現 HTTP 伺服器返回的錯誤頁。 呈現發生在ContentLoading 事件和 DOMContentLoaded 事件之間。

  11. HTTP 伺服器可能會接受身份驗證憑據並返回請求的文件。

  12. WebView2 控制元件呈現返回的文件。 呈現發生在 ContentLoading 事件和 DOMContentLoaded 事件之間。

示例程式

BasicAuthenticationRequeste事件中實現具體的校驗憑證邏輯

 1 private void CoreWebView2_BasicAuthenticationRequested(object? sender, CoreWebView2BasicAuthenticationRequestedEventArgs args)
 2 {
 3     /* 開發者需要非同步顯示UI,以便獲得 CoreWebView2Deferral 物件。
 4      * 該物件將延遲 CoreWebView2 檢查開發者在事件引數上設定的屬性,直到稍後非同步呼叫 Complete 方法。
 5      * 這給了開發者非同步顯示UI的時間。
 6      */
 7     CoreWebView2Deferral deferral = args.GetDeferral();
 8 
 9     // 通過在非同步完成延遲後顯示下載對話方塊,我們避免了在事件處理程式中執行訊息迴圈的潛在可重入性
10     System.Threading.SynchronizationContext.Current.Post((_) =>
11                                                          {
12                                                              using (deferral)
13                                                              {
14                                                                  // 提示終端使用者進行身份驗證時,重要的是向他們顯示請求身份驗證的URI或URI的來源,以便終端使用者知道他們將使用者名稱和密碼提供給誰。
15 
16                                                                  // 向終端使用者顯示挑戰也很重要,因為它可能會為終端使用者提供重要的站點特定資訊,以提供正確的使用者名稱和密碼
17 
18                                                                  // 使用應用程式或UI框架方法從終端使用者獲取輸入。
19 
20                                                                  bool userNameAndPasswordSet = false;
21                                                                  Frm6Auth frm = new Frm6Auth(args.Uri);
22                                                                  DialogResult dialogResult = frm.ShowDialog();
23                                                                  if (dialogResult == DialogResult.OK)
24                                                                  {
25                                                                      args.Response.UserName = frm.UserName;
26                                                                      args.Response.Password = frm.UserPwd;
27                                                                      userNameAndPasswordSet = true;
28                                                                  }
29 
30                                                                  /* TODO 此處要做真正的認證校驗。測試程式只做舉例說明 */
31                                                                  if (args.Response.UserName != "admin" && args.Response.Password != "admin123456")
32                                                                  {
33                                                                      MessageBox.Show("使用者名稱與密碼不正確。", "提示",
34                                                                          MessageBoxButtons.RetryCancel,
35                                                                          MessageBoxIcon.Warning);
36 
37                                                                      userNameAndPasswordSet = false;
38                                                                  }
39 
40                                                                  // 如果我們沒有從終端使用者那裡獲得使用者名稱和密碼。我們取消認證請求,不提供任何認證
41                                                                  if (!userNameAndPasswordSet)
42                                                                  {
43                                                                      args.Cancel = true;
44                                                                  }
45                                                              }
46                                                          }, null);
47 }

Frm6Auth窗體如下

有兩種型別的導航:

  • "伺服器請求的身份驗證"導航。
  • "伺服器為 WebView2 控制元件提供文件"導航。

  第一種型別的導航後,伺服器要求進行身份驗證,並且應用需要再次嘗試這種導航 (使用新的導航 ID) 。 新導航將使用主機應用從事件引數響應物件獲取的任何內容。

  HTTP 伺服器可能需要 HTTP 身份驗證。 在這種情況下,存在第一 個導航,該導航具有上面列出的導航事件。 HTTP 伺服器返回 401 或 407 HTTP 響應 NavigationCompleted ,因此事件具有相應的失敗。 然後,WebView2 呈現空白頁 BasicAuthenticationRequested 並引發事件,這可能會提示使用者輸入憑據。

  • BasicAuthenticationRequested如果取消該事件,則沒有後續導航,並且 WebView2 將保留以顯示空白頁。
  • BasicAuthenticationRequested如果未取消該事件,WebView2 將再次執行初始導航,但這次使用任何提供的憑據。 你將再次看到與之前相同的導航事件。

  如果 HTTP 伺服器不接受憑據,導航將再次因 401 或 407 失敗。 在這種情況下,類 CoreWebView2 例項將再次引發 BasicAuthenticationRequested 事件,並且導航將繼續,如上所述。

  如果 HTTP 伺服器接受憑據,則導航成功。 如果 HTTP 伺服器拒絕身份驗證,則 (通常返回錯誤頁) 。

事件之前和之後導航 BasicAuthenticationRequested 是不同的導航,並且具有不同的導航 ID。導航event args有一個屬性:NavigationId 與 NavigationId 單個導航對應的導航事件緊密結合。 在每個 NavigationId 導航過程中保持不變,如重試。 在下次傳遞事件流期間,使用不同的 NavigationId 方法。

相關文章