Kurz: Zabezpečení webového rozhraní API ASP.NET zaregistrovaného v tenantovi zákazníka
Webová rozhraní API můžou obsahovat informace, které vyžadují ověření a autorizaci uživatelů. Aplikace můžou používat delegovaný přístup, jednat jménem přihlášeného uživatele nebo přístup jenom pro aplikace a při volání chráněných webových rozhraní API jednat pouze jako vlastní identita aplikace.
V tomto kurzu vytvoříme webové rozhraní API, které publikuje delegovaná oprávnění (obory) i oprávnění aplikací (aplikační role). Klientské aplikace, jako jsou webové aplikace, které získávají tokeny jménem přihlášeného uživatele, používají delegovaná oprávnění. Klientské aplikace, jako jsou aplikace démona, které získávají tokeny pro sebe, používají oprávnění aplikace.
V tomto kurzu se naučíte:
Konfigurace webového rozhraní API tp s použitím podrobností o registraci aplikace: Nakonfigurujte webové rozhraní API tak, aby používalo delegovaná oprávnění a oprávnění aplikací zaregistrovaná v registraci aplikace Ochrana koncových bodů webového rozhraní API
Požadavky
Registrace rozhraní API, která zveřejňuje alespoň jeden obor (delegovaná oprávnění) a jednu roli aplikace (oprávnění aplikace), jako je ToDoList.Read. Pokud jste to ještě neudělali, zaregistrujte rozhraní API v centru pro správu Microsoft Entra podle pokynů pro registraci. Ujistěte se, že máte následující:
- ID aplikace (klienta) webového rozhraní API
- ID adresáře (tenanta) webového rozhraní API je zaregistrované.
- Subdoména adresáře (tenanta), kde je zaregistrované webové rozhraní API. Pokud je například vaše primární doménacontoso.onmicrosoft.com, je subdoménou adresáře (tenanta) contoso.
- ToDoList.Read a ToDoList.ReadWrite jako delegovaná oprávnění (obory) vystavená webovým rozhraním API.
- ToDoList.Read.All a ToDoList.ReadWrite.All jako oprávnění aplikace (aplikační role) vystavené webovým rozhraním API.
.NET 7.0 nebo novější.
Visual Studio Code nebo jiný editor kódu.
Vytvoření webového rozhraní API ASP.NET Core
Otevřete terminál a pak přejděte do složky, ve které má být projekt aktivní.
Spusťte následující příkazy:
dotnet new webapi -o ToDoListAPI cd ToDoListAPI
Když se v dialogovém okně zobrazí dotaz, jestli chcete do projektu přidat požadované prostředky, vyberte Ano.
Instalace balíčků
Nainstalujte následující balíčky:
Microsoft.EntityFrameworkCore.InMemory
, který umožňuje použití Entity Framework Core s databází v paměti. Není určen pro produkční použití.Microsoft.Identity.Web
zjednodušuje přidávání podpory ověřování a autorizace do webových aplikací a webových rozhraní API integrovaných s Microsoft identity platform.
dotnet add package Microsoft.EntityFrameworkCore.InMemory
dotnet add package Microsoft.Identity.Web
Konfigurace podrobností o registraci aplikace
Otevřete soubor appsettings.json ve složce aplikace a přidejte podrobnosti o registraci aplikace, které jste zaznamenali po registraci webového rozhraní API.
{
"AzureAd": {
"Instance": "https://Enter_the_Tenant_Subdomain_Here.ciamlogin.com/",
"TenantId": "Enter_the_Tenant_Id_Here",
"ClientId": "Enter_the_Application_Id_Here",
},
"Logging": {...},
"AllowedHosts": "*"
}
Nahraďte následující zástupné symboly, jak je znázorněno na obrázku:
- Nahraďte
Enter_the_Application_Id_Here
ID aplikace (klienta). - Nahraďte
Enter_the_Tenant_Id_Here
id vašeho adresáře (tenanta). - Nahraďte
Enter_the_Tenant_Subdomain_Here
subdoménou adresáře (tenanta).
Přidání role a oboru aplikace
Všechna rozhraní API musí publikovat minimálně jeden obor, označovaný také jako delegovaná oprávnění, aby klientské aplikace úspěšně získaly přístupový token pro uživatele. Rozhraní API by také měla publikovat minimálně jednu roli aplikace pro aplikace, označovanou také jako oprávnění aplikace, aby klientské aplikace získaly přístupový token jako samy, tj. když se nepřihlašují k uživateli.
Tato oprávnění zadáváme v souboru appsettings.json . V tomto kurzu jsme zaregistrovali čtyři oprávnění. ToDoList.ReadWrite a ToDoList.Read jako delegovaná oprávnění a ToDoList.ReadWrite.All a ToDoList.Read.All jako oprávnění aplikace.
{
"AzureAd": {
"Instance": "https://Enter_the_Tenant_Subdomain_Here.ciamlogin.com/",
"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": "*"
}
Přidání schématu ověřování
Schéma ověřování je pojmenováno, když je během ověřování nakonfigurovaná ověřovací služba. V tomto článku použijeme schéma ověřování nosné verze JWT. Přidejte do souboru Programs.cs následující kód, který přidá schéma ověřování.
// Add the following to your imports
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Identity.Web;
// Add authentication scheme
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(builder.Configuration);
Vytvoření modelů
V kořenové složce projektu vytvořte složku s názvem Modely . Přejděte do složky a vytvořte soubor s názvem ToDo.cs a přidejte následující kód. Tento kód vytvoří model s názvem ToDo.
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;
}
Přidání kontextu databáze
Kontext databáze je hlavní třída, která koordinuje funkce Entity Frameworku pro datový model. Tato třída je vytvořena odvozením z Microsoft.EntityFrameworkCore.DbContext třídy. V tomto kurzu používáme databázi v paměti pro účely testování.
V kořenové složce projektu vytvořte složku s názvem DbContext .
Přejděte do této složky a vytvořte soubor s názvem ToDoContext.cs a přidejte do něj následující obsah:
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; } }
Otevřete soubor Program.cs v kořenové složce aplikace a přidejte do souboru následující kód. Tento kód zaregistruje podtřídu nazvanou
DbContext
ToDoContext
jako vymezenou službu v ASP.NET Core zprostředkovateli aplikačních služeb (označuje se také jako kontejner injektáže závislostí). Kontext je nakonfigurovaný tak, aby používal databázi v paměti.// Add the following to your imports using ToDoListAPI.Context; using Microsoft.EntityFrameworkCore; builder.Services.AddDbContext<ToDoContext>(opt => opt.UseInMemoryDatabase("ToDos"));
Přidání kontrolerů
Ve většině případů by kontroler měl více než jednu akci. Obvykle se jedná o akce CRUD (Vytvořit, Číst, Aktualizovat a Odstranit ). V tomto kurzu vytvoříme pouze dvě položky akce. Položka akce pro čtení a položka akce vytvoření, která ukazuje, jak chránit koncové body.
V kořenové složce projektu přejděte do složky Kontrolery .
V této složce vytvořte soubor s názvem ToDoListController.cs . Otevřete soubor a přidejte následující kód kotlové desky:
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(){...} }
Přidání kódu do kontroleru
V této části přidáme kód do zástupných symbolů, které jsme vytvořili. Zde se nezaměřuje na sestavení rozhraní API, ale spíše na jeho ochranu.
Importujte potřebné balíčky. Balíček Microsoft.Identity.Web je obálka MSAL, která nám pomáhá snadno zpracovávat logiku ověřování, například zpracováním ověřování tokenů. Abychom zajistili, že naše koncové body vyžadují autorizaci, používáme balíček Microsoft.AspNetCore.Authorization .
Vzhledem k tomu, že jsme tomuto rozhraní API udělili oprávnění k volání pomocí delegovaných oprávnění jménem uživatele nebo oprávnění aplikace, kde klient volá sám, a ne jménem uživatele, je důležité vědět, jestli volání provádí aplikace jejím vlastním jménem. Nejjednodušším způsobem, jak to udělat, jsou deklarace identity, které zjistí, jestli přístupový token obsahuje volitelnou
idtyp
deklaraci identity. Tatoidtyp
deklarace identity představuje nejjednodušší způsob, jak rozhraní API určit, jestli je token tokenem aplikace nebo tokenem aplikace a uživatele. Doporučujeme povolit volitelnouidtyp
deklaraci identity.idtyp
Pokud deklarace identity není povolená, můžete pomocíroles
deklarací identity ascp
určit, jestli je přístupový token tokenem aplikace nebo tokenem aplikace a uživatele. Přístupový token vydaný Microsoft Entra Externí ID má alespoň jednu ze dvou deklarací identity. Přístupové tokeny vydané uživateli majíscp
deklaraci identity. Přístupové tokeny vydané aplikaci majíroles
deklaraci identity. Přístupové tokeny, které obsahují obě deklarace identity, se vydávají jenom uživatelům, kdescp
deklarace identity určuje delegovaná oprávnění, zatímcoroles
deklarace identity určuje roli uživatele. Přístupové tokeny, které nemají ani jeden, se nebudou respektovat.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"); } }
Přidejte pomocnou funkci, která určuje, jestli vytvářená žádost obsahuje dostatečná oprávnění k provedení zamýšlené akce. Ověřením ID uživatele zkontrolujte, jestli aplikace provádí žádost vlastním jménem, nebo jestli aplikace provádí volání jménem uživatele, který daný prostředek vlastní.
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; }
Připojte definice oprávnění k ochraně tras. Chraňte své rozhraní API přidáním atributu
[Authorize]
do třídy kontroleru. Tím se zajistí, že se akce kontroleru dají volat jenom v případě, že se rozhraní API volá s autorizovanou identitou. Definice oprávnění definují, jaké druhy oprávnění jsou potřeba k provedení těchto akcí.[Authorize] [Route("api/[controller]")] [ApiController] public class ToDoListController: ControllerBase{...}
Přidejte oprávnění ke koncovému bodu GET all a koncovému bodu POST. Použijte metodu RequiredScopeOrAppPermission , která je součástí oboru názvů Microsoft.Identity.Web.Resource . Pak této metodě předáte obory a oprávnění prostřednictvím atributů RequiredScopesConfigurationKey a 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); }
Spuštění rozhraní API
Spusťte rozhraní API, abyste se ujistili, že funguje správně bez chyb, pomocí příkazu dotnet run
. Pokud máte v úmyslu používat protokol HTTPS i během testování, musíte důvěřovat . Vývojový certifikát pro NET.
Úplný příklad tohoto kódu rozhraní API najdete v ukázkovém souboru.