適用於:白色勾勾符號的 Workforce 租戶
外部租戶(了解更多)
本教學課程系列示範如何使用 Microsoft 身分識別平臺來保護 ASP.NET Core Web API,以限制其僅存取授權的使用者和用戶端應用程式。 您建置的 Web API 會使用委派的許可權(範圍)和應用程式許可權(應用程式角色)。
在本教學課程中,您會:
- 建置 ASP.NET Core Web API
- 設定 Web API 以使用其 Microsoft Entra 應用程式註冊詳細資訊
- 保護您的 Web API 端點
- 執行 Web API 以確保其正在接聽 HTTP 要求
先決條件
- 如果您尚未完成 快速入門:呼叫受Microsoft身分識別平台保護的Web API中的步驟。 您不需要複製並執行程式碼範例,但請確保您具有下列項目:
- 來自 Microsoft Entra 系統管理中心的 Web API 應用程式註冊詳細數據,包括用戶端識別碼和租使用者標識碼。
- ToDoList.Read 和 ToDoList.ReadWrite 作為 Web API 公開的委派許可權(範圍)
- ToDoList.Read.All 和 ToDoList.ReadWrite.All 作為 Web API 公開的應用程式許可權(應用程式角色)
- .NET 8.0 SDK 或更新版本。
- Visual Studio Code 或其他程式碼編輯器。
建立新的 ASP.NET Core Web API 專案
若要建立基本 ASP.NET Core Web API 專案,請遵循下列步驟:
在 Visual Studio Code 或任何其他程式碼編輯器上開啟終端機,並流覽至您要建立項目的目錄。
在 .NET CLI 或任何其他命令行工具上執行下列命令。
dotnet new web -o TodoListApi cd TodoListApi
當對話框詢問您是否要信任作者時,請選取 [[是]。
在對話框詢問是否要將必要的資產新增至專案時,選取 [是]。
安裝必要的套件
若要建置、保護及測試 ASP.NET Core Web API,您需要安裝下列套件:
-
Microsoft.EntityFrameworkCore.InMemory
- 可讓您搭配記憶體內部資料庫使用 Entity Framework Core 的套件。 這對於測試用途很有用,但並非專為生產環境使用而設計。 -
Microsoft.Identity.Web
- 一組 ASP.NET 核心連結庫,可簡化將驗證和授權支援新增至與Microsoft身分識別平臺整合的Web應用程式和Web API。
若要安裝套件,請使用:
dotnet add package Microsoft.EntityFrameworkCore.InMemory
dotnet add package Microsoft.Identity.Web
設定應用程式註冊詳細數據
在應用程式資料夾中開啟 appsettings.json 檔案,並新增您在註冊 Web API 之後所記錄的應用程式註冊詳細數據。
{
"AzureAd": {
"Instance": "Enter_the_Authority_URL_Here",
"TenantId": "Enter_the_Tenant_Id_Here",
"ClientId": "Enter_the_Application_Id_Here"
},
"Logging": {...},
"AllowedHosts": "*"
}
取代下列佔位符,如下所示:
- 以您的應用程式 (用戶端) 識別碼取代
Enter_the_Application_Id_Here
。 - 使用您的目錄(租用戶)ID 替換
Enter_the_Tenant_Id_Here
。 - 將
Enter_the_Authority_URL_Here
取代為您的權威 URL,如下一節所述。
應用程式的授權URL
授權單位 URL 指定了 Microsoft 驗證程式庫(MSAL)用於請求令牌的目錄。 您會在員工團隊和外部租戶中用不同的方法建構它,如下所示:
//Instance for workforce tenant
Instance: "https://login.microsoftonline.com/"
使用自訂網址 (選擇性)
"員工租戶不支援自訂網域名稱。"
新增許可權
所有 API 都必須發布至少一個範圍,也稱為委派許可權,用戶端應用程式才能成功取得使用者的存取令牌。 API 也應該發佈至少一個應用程式角色,也稱為應用程式許可權,讓用戶端應用程式自行取得存取令牌,也就是說,當他們未登入使用者時。
我們會在 appsettings.json 檔案中指定這些許可權。 在本教學課程中,您已註冊下列委派和應用程式許可權:
- 委派的許可權:ToDoList.Read 和 ToDoList.ReadWrite。
- 應用程式許可權:ToDoList.Read.All 和 ToDoList.ReadWrite.All。
當使用者或用戶端應用程式呼叫 Web API 時,只有具有這些範圍或許可權的用戶端才獲得存取受保護端點的授權。
{
"AzureAd": {
"Instance": "Enter_the_Authority_URL_Here",
"TenantId": "Enter_the_Tenant_Id_Here",
"ClientId": "Enter_the_Application_Id_Here",
"Scopes": {
"Read": ["ToDoList.Read", "ToDoList.ReadWrite"],
"Write": ["ToDoList.ReadWrite"]
},
"AppPermissions": {
"Read": ["ToDoList.Read.All", "ToDoList.ReadWrite.All"],
"Write": ["ToDoList.ReadWrite.All"]
}
},
"Logging": {...},
"AllowedHosts": "*"
}
在 API 中實作驗證和授權
若要設定驗證和授權,請開啟 program.cs
檔案,並取代其內容下列代碼段:
新增驗證配置
在此 API 中,我們會使用 JSON Web 令牌 (JWT) 持有人配置作為預設驗證機制。 使用 AddAuthentication
方法來註冊 JWT 持有人方案。
// Add required packages to your imports
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Identity.Web;
var builder = WebApplication.CreateBuilder(args);
// Add an authentication scheme
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(builder.Configuration);
建立應用程式的模型
在專案的根資料夾中,建立名為 Models 的資料夾。 流覽至 Models 資料夾,並建立名為 ToDo.cs
的檔案,然後新增下列程式代碼。
using System;
namespace ToDoListAPI.Models;
public class ToDo
{
public int Id { get; set; }
public Guid Owner { get; set; }
public string Description { get; set; } = string.Empty;
}
上述程式代碼會建立名為 ToDo 的模型。 此模型代表應用程式管理的數據。
新增資料庫上下文
接下來,我們會定義資料庫內容類別,以協調數據模型的 Entity Framework 功能。 這個類別繼承自管理應用程式與資料庫之間互動 的 Microsoft.EntityFrameworkCore.DbContext 類別。 若要新增資料庫內容,請遵循下列步驟:
在專案的根資料夾中建立名為 DbContext 的資料夾。
瀏覽至 DbContext 資料夾,並建立名為
ToDoContext.cs
的檔案,然後新增下列程式代碼:using Microsoft.EntityFrameworkCore; using ToDoListAPI.Models; namespace ToDoListAPI.Context; public class ToDoContext : DbContext { public ToDoContext(DbContextOptions<ToDoContext> options) : base(options) { } public DbSet<ToDo> ToDos { get; set; } }
在專案的根資料夾開啟 Program.cs 檔案,並使用下列程式代碼加以更新:
// Add the following to your imports using ToDoListAPI.Context; using Microsoft.EntityFrameworkCore; //Register ToDoContext as a service in the application builder.Services.AddDbContext<ToDoContext>(opt => opt.UseInMemoryDatabase("ToDos"));
在上述代碼段中,我們會將 DB 內容註冊為 ASP.NET Core 應用程式服務提供者中的範圍服務(也稱為相依性插入容器)。 您也可以將 ToDoContext
類別設定為使用 ToDo 清單 API 的記憶體內部資料庫。
設定控制器
控制器通常會實作建立、讀取、更新和刪除 (CRUD) 動作來管理資源。 由於本教學課程更著重於保護 API 端點,所以我們只會在控制器中實作兩個動作專案。 提供一個 "讀取" 動作以檢索所有待辦事項,和一個 "建立" 動作以新增一個新的待辦事項。 請遵循下列步驟,將控制器新增至您的專案:
流覽至專案的根資料夾,並建立名為 Controllers 的資料夾。
在
ToDoListController.cs
資料夾內建立名為 的檔案,並新增下列鍋爐板程式碼:
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.Resource;
using ToDoListAPI.Models;
using ToDoListAPI.Context;
namespace ToDoListAPI.Controllers;
[Authorize]
[Route("api/[controller]")]
[ApiController]
public class ToDoListController : ControllerBase
{
private readonly ToDoContext _toDoContext;
public ToDoListController(ToDoContext toDoContext)
{
_toDoContext = toDoContext;
}
[HttpGet()]
[RequiredScopeOrAppPermission()]
public async Task<IActionResult> GetAsync(){...}
[HttpPost]
[RequiredScopeOrAppPermission()]
public async Task<IActionResult> PostAsync([FromBody] ToDo toDo){...}
private bool RequestCanAccessToDo(Guid userId){...}
private Guid GetUserId(){...}
private bool IsAppMakingRequest(){...}
}
將程式代碼新增至控制器
本節說明如何將程式碼新增至在上一節中建立的控制器樣板。 這裡的重點是保護 API,而不是建置 API。
匯入必要的套件: 套件
Microsoft.Identity.Web
是 MSAL.NET 包裝函式,可協助我們輕鬆處理驗證邏輯,例如處理令牌驗證。 為了確保我們的端點需要授權,我們會使用內建的Microsoft.AspNetCore.Authorization
套件。由於我們授予此 API 的權限可以使用者委派權限或應用程式本身的權限進行呼叫,因此了解應用程式是否在代表自己進行呼叫是很重要的。 若要這麼做,最簡單的方式是尋找存取令牌是否包含
idtyp
選擇性宣告。 此idtyp
宣告是 API 判斷令牌是應用程式令牌或應用程式 + 使用者令牌的最簡單方式。 建議您啟用idtyp
可選聲明。如果
idtyp
宣告未啟用,您可以使用roles
和scp
宣告來判斷存取權杖是應用程式權杖還是應用程式加使用者權杖。 Microsoft Entra ID 所發行的存取權杖至少包含兩個宣告中的一個。 發給使用者的存取令牌具有scp
宣告。 簽發給應用程式的存取令牌包含roles
宣告。 包含這兩個宣告的存取令牌只會發給使用者,其中scp
宣告會指定委派的許可權,而roles
宣告則指定使用者的角色。 沒有持有任何這兩個屬性的存取令牌是不可被接受的。private bool IsAppMakingRequest() { if (HttpContext.User.Claims.Any(c => c.Type == "idtyp")) { return HttpContext.User.Claims.Any(c => c.Type == "idtyp" && c.Value == "app"); } else { return HttpContext.User.Claims.Any(c => c.Type == "roles") && !HttpContext.User.Claims.Any(c => c.Type == "scp"); } }
新增協助程式函式,以判斷提出的要求是否包含足夠的許可權來執行預定的動作。 檢查應用程式是否代表自己提出要求,或應用程式是否代表擁有指定資源的用戶進行呼叫,方法是驗證使用者標識碼。
private bool RequestCanAccessToDo(Guid userId) { return IsAppMakingRequest() || (userId == GetUserId()); } private Guid GetUserId() { Guid userId; if (!Guid.TryParse(HttpContext.User.GetObjectId(), out userId)) { throw new Exception("User ID is not valid."); } return userId; }
插入您的許可權定義來保護路由。 為了保護您的 API,請在控制器類別中新增
[Authorize]
屬性。 這可確保只有在使用授權的身分識別呼叫 API 時,才能呼叫控制器動作。 許可權定義會定義執行這些動作所需的許可權類型。[Authorize] [Route("api/[controller]")] [ApiController] public class ToDoListController: ControllerBase{...}
將許可權新增至 GET 和 POST 端點。 使用屬於 Microsoft.Identity.Web.Resource 命名空間的 RequiredScopeOrAppPermission 方法執行此動作。 然後,您可以透過 RequiredScopesConfigurationKey 和 RequiredAppPermissionsConfigurationKey 属性,將範圍和許可權傳遞至此方法。
[HttpGet] [RequiredScopeOrAppPermission( RequiredScopesConfigurationKey = "AzureAD:Scopes:Read", RequiredAppPermissionsConfigurationKey = "AzureAD:AppPermissions:Read" )] public async Task<IActionResult> GetAsync() { var toDos = await _toDoContext.ToDos! .Where(td => RequestCanAccessToDo(td.Owner)) .ToListAsync(); return Ok(toDos); } [HttpPost] [RequiredScopeOrAppPermission( RequiredScopesConfigurationKey = "AzureAD:Scopes:Write", RequiredAppPermissionsConfigurationKey = "AzureAD:AppPermissions:Write" )] public async Task<IActionResult> PostAsync([FromBody] ToDo toDo) { // Only let applications with global to-do access set the user ID or to-do's var ownerIdOfTodo = IsAppMakingRequest() ? toDo.Owner : GetUserId(); var newToDo = new ToDo() { Owner = ownerIdOfTodo, Description = toDo.Description }; await _toDoContext.ToDos!.AddAsync(newToDo); await _toDoContext.SaveChangesAsync(); return Created($"/todo/{newToDo!.Id}", newToDo); }
設定 API 中間件以使用控制器
接下來,我們會將應用程式設定為辨識並使用控制器來處理 HTTP 要求。 開啟 檔案, program.cs
並新增下列程序代碼,以在相依性插入容器中註冊控制器服務。
builder.Services.AddControllers();
var app = builder.Build();
app.MapControllers();
app.Run();
在上述代碼段中, AddControllers()
方法會藉由註冊必要的服務來準備應用程式以使用控制器,同時 MapControllers()
對應控制器路由來處理傳入的 HTTP 要求。
執行您的 API
執行您的 API,以確保執行時沒有任何錯誤,請使用 命令 dotnet run
。 如果您要即使在測試期間使用 HTTPS 通訊協定,則需要 信任 。NET 的開發憑證。
在終端機中輸入下列命令以啟動應用程式:
dotnet run
類似下列的輸出應該會顯示在終端機中,這可確認應用程式正在執行
http://localhost:{port}
並接聽要求。Building... info: Microsoft.Hosting.Lifetime[0] Now listening on: http://localhost:{port} info: Microsoft.Hosting.Lifetime[0] Application started. Press Ctrl+C to shut down. ...
網頁 http://localhost:{host}
會顯示類似下圖的輸出。 這是因為 API 是在未驗證的情況下呼叫。 若要進行授權的呼叫,請參閱 後續步驟,以取得如何存取受保護 Web API 的指引。
如需此 API 程式代碼的完整範例,請參閱 範例檔案。