使用 Azure API 管理和 Azure AD B2C 保護要從 SPA 取用的無伺服器 API
適用於:所有 API 管理 層
此情節說明如何設定 Azure API 管理執行個體來保護 API。 我們將使用 Azure AD B2C SPA (驗證碼 + PKCE) 流程來取得權杖,同時透過 API 管理利用 EasyAuth 來保護 Azure Functions 後端。
如需 API 授權的概念概觀,請參閱 APIM 中的 API 驗證和授權。
目標
我們將了解如何在簡易情節中以 Azure Functions 和 Azure AD B2C 來使用 API 管理。 您將建立 JavaScript (JS) 應用程式來呼叫 API,以使用 Azure AD B2C 讓使用者登入。 然後,您將使用 API 管理的 validate-jwt、CORS 和「依金鑰限制速率」原則功能來保護後端 API。
為了深入防禦,我們接著使用 EasyAuth 在後端 API 內再次驗證權杖,並確保 API 管理是唯一可以呼叫 Azure Functions 後端的服務。
您將學到什麼
- 在 Azure Active Directory B2C 中設定單頁應用程式和後端 API
- 建立 Azure Functions 後端 API
- 將 Azure Functions API 匯入 Azure API 管理
- 在 Azure API 管理中保護 API
- 透過 Microsoft 身分識別平台程式庫 (MSAL.js) 呼叫 Azure Active Directory B2C 授權端點
- 儲存 HTML/Vanilla JS 單頁應用程式,並從 Azure Blob 儲存體端點提供此應用程式
必要條件
若要依照本文中的步驟進行,您必須有:
- Azure (StorageV2) 一般用途 V2 儲存體帳戶來裝載前端 JS 單頁應用程式。
- Azure APIM 執行個體 (任何階層皆可,包括「取用」,但此層沒有適用於完整案例的某些功能 (rate-limit-by-key 和專用虛擬 IP),本文後續會在適當處指出這些限制)。
- 空的 Azure 函數應用程式 (在取用方案上執行 V3.1 .NET Core 執行階段) 來裝載呼叫為 API
- Azure AD B2C 租用戶,連結至訂用帳戶。
在實務上,雖然您會在生產工作負載中的相同區域使用資源,但在此操作說明文章中,部署區域並不重要。
概觀
以下舉例說明此流程完成之後使用中的元件及其之間的流程。
以下為步驟的快速概觀:
以範圍和授與 API 存取權建立 Azure AD B2C 呼叫 (前端、API 管理) 和 API 應用程式
建立註冊和登入原則,讓使用者使用 Azure AD B2C 登入
使用新的 Azure AD B2C 用戶端識別碼和金鑰來設定 API 管理,在開發人員主控台啟用 OAuth2 使用者授權
建立函式 API
設定函式 API 以新的 Azure AD B2C 用戶端識別碼和金鑰來啟用 EasyAuth,並鎖定 APIM VIP
在 API 管理中建立 API 定義
設定 API 管理 API 組態的 Oauth2
設定 CORS 原則和新增 validate-jwt 原則,以驗證每個傳入要求的 OAuth 權杖
組建呼叫端應用程式以取用 API
上傳 JS SPA 範例
使用新的 Azure AD B2C 用戶端識別碼和金鑰來設定範例 JS 用戶端應用程式
測試用戶端應用程式
提示
閱讀本文件時,我們會擷取很多資訊和線索等,開啟文字編輯器來暫時儲存下列組態項目會很方便。
B2C BACKEND CLIENT ID: B2C BACKEND CLIENT SECRET KEY: B2C BACKEND API SCOPE URI: B2C FRONTEND CLIENT ID: B2C USER FLOW ENDPOINT URI: B2C WELL-KNOWN OPENID ENDPOINT: B2C POLICY NAME: Frontendapp_signupandsignin FUNCTION URL: APIM API BASE URL: STORAGE PRIMARY ENDPOINT URL:
設定後端應用程式
在入口網站中開啟 Azure AD B2C 刀鋒視窗,然後執行下列步驟。
選取 [應用程式註冊] 索引標籤
按一下 [新增註冊] 按鈕。
從 [重新導向 URI] 選取方塊中選擇 [Web]。
現在設定 [顯示名稱],選擇的名稱應該獨特又胋切所建立的服務。 在此範例中,我們使用的名稱是「後端應用程式」。
使用預留位置來表示回覆 URL,例如 'https://jwt.ms' (Microsoft 擁有的權杖解碼網站),稍後會更新這些 URL。
在任何身分識別提供者或組織目錄 (用於使用者流程中驗證使用者) 選項中,務必選取「帳戶」
在此範例中,因為目前不需要 offline_access 權限,取消核取 [授與管理員同意] 方塊。
按一下 [註冊]。
記錄後端應用程式用戶端識別碼,供稍後使用 (顯示在 [應用程式 (用戶端) 識別碼] 下)。
選取 [憑證及祕密] 索引標籤 (在 [管理] 下),然後按一下 [新增用戶端密碼] 以產生驗證金鑰 (接受預設設定,然後按一下 [新增])。
按一下 [新增] 後,將金鑰 (在 [值] 下方) 當作「後端用戶端密碼」複製到安全之處,供稍後使用 - 請注意,此對話方塊是您複製此金鑰的「唯一」機會。
現在,選取 [公開 API] 索引標籤 (在 [管理] 下)。
將會提示您設定 AppID URI,請選取並記錄預設值。
建立並命名函式 API 的範圍 "Hello",您可以對所有可輸入的選項使用 'Hello' 一詞,記錄填入的 [完整範圍值] URI,然後按一下 [新增範圍]。
選取入口網站左上方的 [Azure AD B2C] 階層連結,返回 Azure AD B2C 刀鋒視窗的根目錄。
注意
Azure AD B2C 範圍實際上是 API 內的權限,可供其他應用程式從其應用程式透過 API 存取刀鋒視窗來要求存取,事實上您只是為呼叫的 API 建立應用程式權限。
設定前端應用程式
- 選取 [應用程式註冊] 索引標籤
- 按一下 [新增註冊] 按鈕。
- 從 [重新導向 URI] 選取方塊中選擇 [單頁應用程式 (SPA)]。
- 現在設定 [顯示名稱] 和 [AppID URI],選擇的值應該獨特又貼近將使用此 Azure Active Directory B2C 應用程式註冊的前端應用程式。 在此範例中,您可以使用「前端應用程式」
- 如同第一次應用程式註冊,將支援的帳戶類型選擇保持預設 (在使用者流程中驗證使用者)
- 使用預留位置來表示回覆 URL,例如 'https://jwt.ms' (Microsoft 擁有的權杖解碼網站),稍後會更新這些 URL。
- 保持勾選 [授與管理員同意] 方塊
- 按一下 [註冊]。
- 記錄前端應用程式用戶端識別碼,供稍後使用 (顯示在 [應用程式 (用戶端) 識別碼] 下)。
- 切換至 [API 權限] 索引標籤。
- 按一下 [新增權限] 及 [我的 API] 以授與存取權給後端應用程式,選取 [後端應用程式],選取 [權限],選取您在上一節建立的範圍,然後按一下 [新增權限]
- 按一下 [授與 {tenant} 的管理員同意],然後從快顯視窗對話方塊中按一下 [是]。 此快顯同意「前端應用程式」使用稍早建立的「後端應用程式」中定義的權限 "hello"。
- 現在,應用程式的所有權限在 [狀態] 欄下應該都顯示為綠色勾號
建立「註冊和登入」使用者流程
選取 Azure AD B2C 階層連結,返回 B2C 刀鋒視窗的根目錄。
切換至 [使用者流程] 索引標籤 (在 [原則] 下)。
按一下 [新增使用者流程]
選擇 [註冊和登入] 使用者流程類型,選取 [建議] 及 [建立]
命名原則並記錄名稱,供稍後使用。 在此範例中,您可以使用 "Frontendapp_signupandsignin",請注意,開頭會加上 "B2C_1_",變成 "B2C_1_Frontendapp_signupandsignin"
在 [識別提供者] 和 [本機帳戶] 下,勾選 [電子郵件註冊] (或 [使用者識別碼註冊],視 B2C 租用戶的設定而定),然後按一下 [確定]。 這樣設定是因為我們要註冊本地 B2C 帳戶,而不是交給另一個身分識別提供者 (例如社交識別提供者) 採用使用者現有的社交媒體帳戶。
將 MFA 和條件式存取設定保持預設。
在 [使用者屬性和宣告] 下,按一下 [顯示更多...],然後選擇您想讓使用者輸入並在權杖中傳回的宣告選項。 至少勾選收集 [顯示名稱] 和 [電子郵件地址],以及傳回 [顯示名稱] 和 [電子郵件地址] (特別注意,收集的電子郵件地址是單數,要求傳回的電子郵件地址是多數),按一下 [確定],然後按一下 [建立]。
在清單中按一下您建立的使用者流程,然後按一下 [執行使用者流程] 按鈕。
此動作會開啟 [執行使用者流程] 刀鋒視窗,請選取前端應用程式,複製使用者流程端點,並儲存供稍後使用。
複製並儲存頂端的連結,記錄為「已知 openid 設定端點」供稍後使用。
注意
B2C 原則可讓您公開 Azure AD B2C 登入端點,而能夠擷取不同的資料元件並以不同方式讓使用者登入。
在此案例中,我們已設定註冊或登入流程 (原則)。 這也公開已知的設定端點,在這兩種情況下,URL 中以 "p=" 查詢字串參數識別我們建立的原則。
完成後,您現在有可運作的企業對消費者身分識別平台,可讓使用者登入多個應用程式。
建立函式 API
切換回 Azure 入口網站中的標準 Microsoft Entra 租用戶,讓我們再次於訂用帳戶中設定項目。
移至 Azure 入口網站的 [函數應用程式] 刀鋒視窗,開啟空的函數應用程式,然後按一下 [函式],再按一下 [新增]。
在出現的飛出視窗中,選擇 [在入口網站中開發],在 [選取範本] 下選擇 [HTTP 觸發程式],然後在 [範本詳細資料] 下命名為 'hello' 且授權層級設定為「函式」,然後選取 [新增]。
切換至 [程式碼 + 測試] 刀鋒視窗,將下方的範例程式碼複製貼上,以「覆蓋現有的程式碼」。
選取 [儲存]。
using System.Net; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Primitives; public static async Task<IActionResult> Run(HttpRequest req, ILogger log) { log.LogInformation("C# HTTP trigger function processed a request."); return (ActionResult)new OkObjectResult($"Hello World, time and date are {DateTime.Now.ToString()}"); }
提示
您剛才貼上的 C# 指令碼函式程式碼只是將一行記錄到函式記錄,然後傳回 "Hello World" 文字,還有一些動態資料 (日期和時間)。
從左側刀鋒視窗中選取 [整合],然後按一下 [觸發程式] 方塊內的 HTTP (req) 連結。
從 [選取的 HTTP 方法] 下拉式清單中,取消核取 HTTP POST 方法,只選取 GET,然後按一下 [儲存]。
切換回 [程式碼 + 測試] 索引標籤,按一下 [取得函式 URL],然後複製出現的 URL,並儲存供稍後使用。
注意
您剛才建立的繫結只是告訴 Functions,針對您剛才複製的 URL (
https://yourfunctionappname.azurewebsites.net/api/hello?code=secretkey
) 回應匿名 HTTP GET 要求。 現在我們有可調整的無伺服器 HTTPS API,能夠傳回非常簡單的承載。現在可以使用您剛才在上方複製並儲存的 URL 版本,從網頁瀏覽器測試呼叫此 API。 您也可以移除 URL 的查詢字串參數 "?code=secretkey" 部分,然後再次測試,以證明 Azure Functions 會傳回 401 錯誤。
設定和保護函式 API
需要設定函式應用程式中的兩個額外區域 (授權和網路限制)。
首先,讓我們設定驗證/授權,請透過階層連結巡覽回函式應用程式的根目錄刀鋒視窗。
接下來選取 [驗證] (在 [設定] 下)。
按一下 [新增識別提供者]
在 [識別提供者] 下拉式清單中選取 [Microsoft]
針對 [應用程式註冊],選取 [提供現有應用程式註冊的詳細資料]
將後端應用程式的用戶端識別碼 (從 Azure AD B2C) 貼到 [應用程式 (用戶端) 識別碼] 方塊中 (我們稍早已記錄此設定)。
從註冊和登入原則中,將已知 open-id 設定端點貼到 [簽發者 URL] 方塊中 (我們稍早已記錄此設定)。
將後端應用程式的用戶端密碼貼到適當方塊中 (我們稍早已記錄此設定)。
針對 [未驗證的要求],選取 [HTTP 401 未經授權:建議用於 API]
按一下 [儲存] (在刀鋒視窗左上方)。
重要
現在,您的函式 API 已部署,如果未提供正確的 JWT 作為 Authorization: Bearer 標頭,應該會擲回 401 回應,如果存在有效的要求,應該會傳回資料。 您已在 EasyAuth 中設定 [使用 Microsoft Entra ID 登入] 選項來處理未經驗證的要求,增加額外的深度防禦安全性。
我們仍未套用 IP 安全性,如果您具備有效的金鑰和 OAuth2 權杖,則可供任何人從任何地方呼叫 - 我們最好強制所有要求都透過 API 管理到來。
如果您使用 APIM 取用層、基本 v2 層和標準 v2 層,則允許清單中沒有專用的 Azure APIM 虛擬 IP 會有函式存取限制。 在 Azure API 管理 傳統(專用)層中,VIP 是單一租使用者,且資源存留期。 針對共用基礎結構上執行的層,可透過共用秘密函式金鑰 (位於上方所複製的 URI 部分中) 來鎖定 API 呼叫。 此外,對於這些層,以下的步驟 12-17 不適用。
從 App Service / Azure Functions 入口網站關閉 [驗證] 刀鋒視窗。
開啟「入口網站的 API 管理刀鋒視窗」,然後開啟「您的執行個體」。
記錄 [概觀] 索引標籤上顯示的私人 VIP。
返回「入口網站的 Azure Functions 刀鋒視窗」,然後再次開啟「您的執行個體」。
選取 [網路],然後選取 [設定存取限制]
按一下 [新增規則],然後以 xx.xx.xx.xx/32 格式輸入上述步驟 3 中複製的 VIP。
如果您想要繼續與函式入口網站互動,並執行下列選擇性步驟,則也應該在這裡新增您自己的公用 IP 位址或 CIDR 範圍。
一旦清單中有允許項目,Azure 會新增隱含拒絕規則來封鎖其他所有位址。
您必須將 CIDR 格式的位址區塊新增至 IP 限制面板。 需要新增單一位址時,例如 API 管理 VIP,您必須以 xx.xx.xx.xx/32 格式新增。
注意
現在,除了透過 API 管理或您的位址,應該無法從任何地方呼叫您的函式 API。
開啟「API 管理刀鋒視窗」,然後開啟「您的執行個體」。
選取 [API] 刀鋒視窗 (在 [API] 下)。
從 [新增 API] 窗格中,選擇 [函數應用程式],然後從快顯視窗頂端選取 [完整]。
按一下 [瀏覽],選擇內已裝載 API 的函數應用程式,然後按一下 [選取]。 接著按一下 [選取]。
為 API 提供名稱和描述,供 API 管理內部使用,並新增至「無限制」產品。
複製並記錄 API 的 [基底 URL],然後按一下 [建立]。
按一下 [設定] 索引標籤,然後在 [訂用帳戶] 下,關閉 [需要訂用帳戶] 核取方塊,因為在此案例中,我們會使用 Oauth JWT 權杖來限制速率。 請注意,如果您使用取用層,則實際執行環境中仍需要如此。
提示
如果使用 APIM 的取用層,則沒有現成的無限制產品可用。 反之,請巡覽至 [API] 下的 [產品],然後按 [新增]。 輸入 "Unlimited" 作為產品名稱和描述,然後從畫面左下方出現的 [+] API 中選取您剛才新增的 API。 選取 [已發行] 核取方塊。 其餘項目都保持預設。 最後,按 [建立] 按鈕。 這樣會建立「無限制」產品並指派給您的 API。 稍後可以自訂您的新產品。
設定和擷取正確的儲存體端點設定
在 Azure 入口網站中開啟儲存體帳戶刀鋒視窗
選取您建立的帳戶,然後從 [設定] 區段中選取 [靜態網站] 刀鋒視窗 (如果沒看到 [靜態網站] 選項,請檢查您是否已建立 V2 帳戶)。
將靜態虛擬主機功能設定為 [已啟用],並將索引文件名稱設定為 'index.html',然後按一下 [儲存]。
記下 [主要端點] 的內容供稍後使用,因為前端網站將裝載於此位置。
提示
您可以使用 Azure Blob 儲存體 + CDN 重寫,或 Azure App Service 來裝載 SPA,但 Blob 儲存體的靜態網站裝載功能提供預設容器,可從 Azure 儲存體供應靜態 Web 內容 / html / js / css,並為我們推斷一個免處理的預設頁面。
設定 CORS 和 validate-jwt 原則
不論使用哪個 APIM 層,請一律遵循下列各節。 儲存體帳戶 URL 來自您在本文開頭的必要條件中提供的儲存體帳戶。
切換至入口網站的 API 管理刀鋒視窗,然後開啟您的執行個體。
選取 [API],然後選取 [所有 API]。
在 [輸入處理] 下,按一下程式碼檢視按鈕 [</>] 以顯示原則編輯器。
編輯輸入區段,將下列 xml 貼上,變成如下所示。
在原則中取代下列參數
{PrimaryStorageEndpoint} (您在上一節複製的「主要儲存體端點」) {b2cpolicy-known-openid} (您稍早複製的「已知 openid 設定端點」) 和 {backend-api-application-client-id} (後端 API的 B2C 應用程式/用戶端識別碼) 換成先前儲存的正確值。
如果使用 APIM 的取用層,則應該移除這兩個 rate-limit-by-key 原則,因為使用 Azure APIM 的取用層時沒有此原則可用。
<inbound> <cors allow-credentials="true"> <allowed-origins> <origin>{PrimaryStorageEndpoint}</origin> </allowed-origins> <allowed-methods preflight-result-max-age="120"> <method>GET</method> </allowed-methods> <allowed-headers> <header>*</header> </allowed-headers> <expose-headers> <header>*</header> </expose-headers> </cors> <validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Unauthorized. Access token is missing or invalid." require-expiration-time="true" require-signed-tokens="true" clock-skew="300"> <openid-config url="{b2cpolicy-well-known-openid}" /> <required-claims> <claim name="aud"> <value>{backend-api-application-client-id}</value> </claim> </required-claims> </validate-jwt> <rate-limit-by-key calls="300" renewal-period="120" counter-key="@(context.Request.IpAddress)" /> <rate-limit-by-key calls="15" renewal-period="60" counter-key="@(context.Request.Headers.GetValueOrDefault("Authorization","").AsJwt()?.Subject)" /> </inbound>
注意
現在,Azure APIM 能夠回應來自 JavaScript SPA 應用程式的跨原點要求,而且在將要求轉送至函式 API「之前」,還會對傳遞的 JWT 驗證權杖執行節流、速率限制和預先驗證。
恭喜,現在 Azure AD B2C、API 管理和 Azure Functions 已一起運作來發行、保護及取用 API!
提示
如果使用 APIM 取用層,您可以依呼叫率配額來限制 (請參閱此處),而非依 JWT 主體或傳入 IP 位址來限制速率 (「取用」層目前不支援依金鑰限制呼叫率原則)。 由於此範例是 JavaScript 單頁應用程式,我們只針對速率限制和計費呼叫來使用 API 管理金鑰。 實際的授權和驗證由 Azure AD B2C 負責,並封裝在 JWT 中,所以驗證兩次,一次是由 API 管理,另一次是由後端 Azure 函式。
將 JavaScript SPA 範例上傳至靜態儲存體
仍在儲存體帳戶刀鋒視窗中,從 [Blob 服務] 區段中選取 [容器] 刀鋒視窗,然後按一下右側窗格中出現的 $web 容器。
在本機電腦上將下列程式碼儲存為 index.html 檔案,然後將 index.html 檔案上傳至 $web 容器。
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BmbxuPwQa2lc/FVzBcNJ7UAyJxM6wuqIj61tLrc4wSX0szH/Ev+nYRRuWlolflfl" crossorigin="anonymous"> <script type="text/javascript" src="https://alcdn.msauth.net/browser/2.11.1/js/msal-browser.min.js"></script> </head> <body> <div class="container-fluid"> <div class="row"> <div class="col-md-12"> <nav class="navbar navbar-expand-lg navbar-dark bg-dark"> <div class="container-fluid"> <a class="navbar-brand" href="#">Azure Active Directory B2C with Azure API Management</a> <div class="navbar-nav"> <button class="btn btn-success" id="signinbtn" onClick="login()">Sign In</a> </div> </div> </nav> </div> </div> <div class="row"> <div class="col-md-12"> <div class="card" > <div id="cardheader" class="card-header"> <div class="card-text"id="message">Please sign in to continue</div> </div> <div class="card-body"> <button class="btn btn-warning" id="callapibtn" onClick="getAPIData()">Call API</a> <div id="progress" class="spinner-border" role="status"> <span class="visually-hidden">Loading...</span> </div> </div> </div> </div> </div> </div> <script lang="javascript"> // Just change the values in this config object ONLY. var config = { msal: { auth: { clientId: "{CLIENTID}", // This is the client ID of your FRONTEND application that you registered with the SPA type in Azure Active Directory B2C authority: "{YOURAUTHORITYB2C}", // Formatted as https://{b2ctenantname}.b2clogin.com/tfp/{b2ctenantguid or full tenant name including onmicrosoft.com}/{signuporinpolicyname} redirectUri: "{StoragePrimaryEndpoint}", // The storage hosting address of the SPA, a web-enabled v2 storage account - recorded earlier as the Primary Endpoint. knownAuthorities: ["{B2CTENANTDOMAIN}"] // {b2ctenantname}.b2clogin.com }, cache: { cacheLocation: "sessionStorage", storeAuthStateInCookie: false } }, api: { scopes: ["{BACKENDAPISCOPE}"], // The scope that we request for the API from B2C, this should be the backend API scope, with the full URI. backend: "{APIBASEURL}/hello" // The location that we'll call for the backend api, this should be hosted in API Management, suffixed with the name of the API operation (in the sample this is '/hello'). } } document.getElementById("callapibtn").hidden = true; document.getElementById("progress").hidden = true; const myMSALObj = new msal.PublicClientApplication(config.msal); myMSALObj.handleRedirectPromise().then((tokenResponse) => { if(tokenResponse !== null){ console.log(tokenResponse.account); document.getElementById("message").innerHTML = "Welcome, " + tokenResponse.account.name; document.getElementById("signinbtn").hidden = true; document.getElementById("callapibtn").hidden = false; }}).catch((error) => {console.log("Error Signing in:" + error); }); function login() { try { myMSALObj.loginRedirect({scopes: config.api.scopes}); } catch (err) {console.log(err);} } function getAPIData() { document.getElementById("progress").hidden = false; document.getElementById("message").innerHTML = "Calling backend ... " document.getElementById("cardheader").classList.remove('bg-success','bg-warning','bg-danger'); myMSALObj.acquireTokenSilent({scopes: config.api.scopes, account: getAccount()}).then(tokenResponse => { const headers = new Headers(); headers.append("Authorization", `Bearer ${tokenResponse.accessToken}`); fetch(config.api.backend, {method: "GET", headers: headers}) .then(async (response) => { if (!response.ok) { document.getElementById("message").innerHTML = "Error: " + response.status + " " + JSON.parse(await response.text()).message; document.getElementById("cardheader").classList.add('bg-warning'); } else { document.getElementById("cardheader").classList.add('bg-success'); document.getElementById("message").innerHTML = await response.text(); } }).catch(async (error) => { document.getElementById("cardheader").classList.add('bg-danger'); document.getElementById("message").innerHTML = "Error: " + error; }); }).catch(error => {console.log("Error Acquiring Token Silently: " + error); return myMSALObj.acquireTokenRedirect({scopes: config.api.scopes, forceRefresh: false}) }); document.getElementById("progress").hidden = true; } function getAccount() { var accounts = myMSALObj.getAllAccounts(); if (!accounts || accounts.length === 0) { return null; } else { return accounts[0]; } } </script> </body> </html>
瀏覽至您先前在上一節儲存的靜態網站主要端點。
注意
恭喜,您剛才已將 JavaScript 單頁應用程式部署至 Azure 儲存體靜態內容裝載。 由於尚未以您的 Azure AD B2C 詳細資料來設定 JS 應用程式,頁面開啟時沒有作用。
設定適用於 Azure AD B2C 的 JavaScript SPA
- 現在我們已完全了解:我們可以使用適當的 API 管理 API 位址和正確的 Azure AD B2C 應用程式/用戶端識別碼來設定 SPA。
- 返回 Azure 入口網站儲存體刀鋒視窗
- 選取 [容器] (在 [設定] 下)
- 從清單中選取 '$web' 容器
- 從清單中選取 index.html Blob
- 按一下 [編輯]
- 將 MSAL config 區段中的 auth 值更新為符合您稍早在 B2C 中註冊的「前端」應用程式。 參考程式碼註解中的提示,以了解 config 值的模樣。 authority 值的格式必須為 https://{b2ctenantname}.b2clogin.com/tfp/{b2ctenantname}.onmicrosoft.com}/{signupandsigninpolicyname},如果您已使用我們的範例名稱,而且 b2c 租用戶稱為 'contoso',則 authority 應該是 'https://contoso.b2clogin.com/tfp/contoso.onmicrosoft.com/Frontendapp_signupandsignin'。
- 將 api 值設定為符合後端位址 (您稍早記錄的 API 基底 URL,稍早已記錄「後端應用程式」的 'b2cScopes' 值)。
- 按一下 [儲存]
設定 Azure AD B2C 前端應用程式的重新導向 URI
開啟 Azure AD B2C 刀鋒視窗,然後巡覽至 JavaScript 前端應用程式的應用程式註冊。
按一下 [重新導向 URI],並刪除我們稍早輸入的預留位置 'https://jwt.ms'。
新增主要 (儲存體) 端點的新 URI (去掉尾端斜線)。
注意
此設定可讓前端應用程式的用戶端從 B2C Azure AD 收到具有適當宣告的存取權杖。 SPA 能夠在呼叫後端 API 時,在 https 標頭中將此權杖新增為持有人權杖。
在將要求傳遞至接收端 Azure 函式 API 的要求、新增函式安全性金鑰之前,API 管理會依 Azure 識別碼 (使用者) 發出的 JWT 主體,並依呼叫端的 IP 位址 (視 API 管理的服務層級而定,見上述附註),預先驗證權杖、限制對端點的呼叫速率。 SPA 會在瀏覽器中呈現回應。
恭喜,您已設定 Azure AD B2C、Azure API 管理、Azure Functions、Azure App Service 授權來完美協調運作!
現在,我們有一個簡單的應用程式和簡單的受保護 API,接著來測試。
測試用戶端應用程式
- 開啟您從稍早建立的儲存體帳戶中記下的應用程式範例 URL。
- 按一下右上角的 [登入],這樣會彈出 Azure AD B2C 註冊或登入設定檔。
- 應用程式應該會以 B2C 設定檔名稱來歡迎您。
- 現在,按一下 [呼叫 API],頁面應該會更新為從受保護 API 傳回的值。
- 如果您「重複地」按一下 [呼叫 API] 按鈕,而且您在 API 管理的開發人員層或更新層級執行,應該會發現解決方案開始限制 API 的速率,而應用程式中應該會以適當的訊息回報此功能。
大功告成!
您可以調整和編輯上述步驟,以採取許多不同方式來使用 API 管理與 Azure AD B2C。
下一步
- 深入了解 Microsoft Entra ID 和 OAuth2.0。
- 查看更多有關 API 管理的 視訊 。
- 如需其他保護後端服務的方式,請參閱相互憑證驗證。
- 建立 API 管理服務執行個體。
- 管理第一個 API。