Kurz: Zabezpečení webového rozhraní API ASP.NET Core zaregistrovaného v externím tenantovi
Tato série kurzů ukazuje, jak zabezpečit zaregistrované webové rozhraní API v externím tenantovi. V tomto kurzu vytvoříte webové rozhraní API ASP.NET Core, které publikuje delegovaná oprávnění (obory) i oprávnění aplikace (role aplikací).
V tomto kurzu;
- Konfigurace webového rozhraní API pro použití 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
- Je zaregistrované ID adresáře (tenanta) webového rozhraní API.
- Subdoména adresáře (tenanta) místa, kde je zaregistrované webové rozhraní API. Pokud je například vaše primární doména contoso.onmicrosoft.com, je subdoména vašeho 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 (role aplikací) vystavená webovým rozhraním API.
.NET 7.0 SDK 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 přejděte do složky, ve které má projekt žít.
Spusťte následující příkazy:
dotnet new webapi -o ToDoListAPI cd ToDoListAPI
Když se zobrazí dialogové okno s dotazem, jestli chcete do projektu přidat požadované prostředky, vyberte Ano.
Instalace balíčků
Nainstalujte následující balíčky:
Microsoft.EntityFrameworkCore.InMemory
umožňuje použití Entity Framework Core s databází v paměti. Není určen pro použití v produkčním prostředí.Microsoft.Identity.Web
zjednodušuje přidávání podpory ověřování a autorizace do webových aplikací a webových rozhraní API integrujících se službou Microsoft Identity Platform.
dotnet add package Microsoft.EntityFrameworkCore.InMemory
dotnet add package Microsoft.Identity.Web
Konfigurace podrobností registrace aplikace
Otevřete soubor appsettings.json ve složce aplikace a přidejte podrobnosti o registraci aplikace, které jste si poznamenali 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:
- Nahraďte
Enter_the_Application_Id_Here
ID vaší 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).
Použití vlastní domény URL (volitelné)
Pomocí vlastní domény plně označte adresu URL ověřování. Z pohledu uživatele zůstanou uživatelé ve vaší doméně během procesu ověřování místo přesměrování na ciamlogin.com název domény.
Pokud chcete použít vlastní doménu, postupujte takto:
Pomocí kroků v části Povolit vlastní domény URL pro aplikace v externích tenantech povolte pro externího tenanta vlastní doménu URL.
Otevřete soubor appsettings.json :
- Aktualizujte hodnotu
Instance
vlastnosti na https://Enter_the_Custom_Domain_Here/Enter_the_Tenant_ID_Herehodnotu . NahraďteEnter_the_Custom_Domain_Here
vlastní doménou URL aEnter_the_Tenant_ID_Here
ID tenanta. Pokud nemáte ID tenanta, přečtěte si, jak si přečíst podrobnosti o tenantovi. - Přidejte
knownAuthorities
vlastnost s hodnotou [Enter_the_Custom_Domain_Here].
- Aktualizujte hodnotu
Po provedení změn souboru appsettings.json , pokud je vaše vlastní doména URL login.contoso.com a ID vašeho tenanta je aaaabbbb-0000-cccc-1111-dddd2222eeeee, měl by váš soubor vypadat podobně jako následující fragment kódu:
{
"AzureAd": {
"Instance": "https://login.contoso.com/aaaabbbb-0000-cccc-1111-dddd2222eeee",
"TenantId": "Enter_the_Tenant_Id_Here",
"ClientId": "Enter_the_Application_Id_Here",
"KnownAuthorities": ["login.contoso.com"]
},
"Logging": {...},
"AllowedHosts": "*"
}
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 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 o sobě, tj. když se nepřihlašují uživateli.
Tato oprávnění zadáme do 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 při konfiguraci ověřovací služby během ověřování. V tomto článku používáme schéma ověřování nosné ověřování JWT. Do souboru Programs.cs přidejte 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ů
Vytvořte složku s názvem Models v kořenové složce projektu. Přejděte do složky a vytvořte soubor s názvem ToDo.cs 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 Framework pro datový model. Tato třída je vytvořena odvozením z Microsoft.EntityFrameworkCore.DbContext třídy. V tomto kurzu používáme k testování databázi v paměti.
Vytvořte složku s názvem DbContext v kořenové složce projektu.
Přejděte do této složky a vytvořte soubor s názvem ToDoContext.cs do tohoto souboru přidejte 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 do souboru přidejte následující kód. Tento kód zaregistruje podtřídu
DbContext
volanouToDoContext
jako službu s vymezeným oborem ve zprostředkovateli aplikační služby ASP.NET Core (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 vytvoření, čtení, aktualizace a odstranění (CRUD). V tomto kurzu vytvoříme pouze dvě položky akce. Přečtěte si všechny položky akce a položku vytvoření akce, abyste si ukázali, jak chránit koncové body.
Přejděte do složky Kontrolery v kořenové složce projektu.
Vytvořte soubor s názvem ToDoListController.cs uvnitř této složky. Otevřete soubor a pak přidejte následující kód kotlového štítku:
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. Tady je fokus na vytváření 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 zpracovat logiku ověřování, například zpracováním ověřování tokenů. Abychom zajistili, že naše koncové body vyžadují autorizaci, použijeme balíček Inbuilt Microsoft.AspNetCore.Authorization .
Vzhledem k tomu, že jsme udělili oprávnění k volání tohoto rozhraní API buď pomocí delegovaných oprávnění jménem uživatele nebo aplikace, kde klient volá jako sám sebe, a ne jménem uživatele, je důležité vědět, jestli volání provádí aplikace vlastním jménem. Nejjednodušší způsob, jak to udělat, je deklarace identity, abyste zjistili, jestli přístupový token obsahuje volitelnou
idtyp
deklaraci identity. Tatoidtyp
deklarace identity je nejjednodušší způsob, jak rozhraní API určit, jestli je tokenem aplikace nebo tokenem aplikace + token uživatele. Doporučujeme povolit volitelnouidtyp
deklaraci identity.idtyp
Pokud deklarace identity není povolená, můžete pomocíroles
scp
deklarací identity určit, jestli se jedná o přístupový token aplikace nebo token 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é pro 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í být dodrženy ani jeden.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 provedený požadavek obsahuje dostatečná oprávnění k provedení zamýšlené akce. Zkontrolujte, jestli aplikace provádí žádost vlastním jménem nebo jestli aplikace volá jménem uživatele, který daný prostředek vlastní, tím, že ověří ID uživatele.
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
[Authorize]
atributu do třídy kontroleru. Tím se zajistí, že akce kontroleru lze volat pouze 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 všem koncovým bodům GET a koncovému bodu POST. Použijte metodu RequiredScopeOrAppPermission , která je součástí oboru názvů Microsoft.Identity.Web.Resource . Pak předáte obory a oprávnění této metodě prostřednictvím RequiredScopesConfigurationKey a RequiredAppPermissionsConfigurationKey atributy.
[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
Spuštěním rozhraní API ověřte, že je správně spuštěný 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 net
Úplný příklad tohoto kódu rozhraní API najdete v ukázkovém souboru.