Zelfstudie: Een ASP.NET Core-web-API beveiligen die is geregistreerd in een externe tenant
Deze reeks zelfstudies laat zien hoe u een geregistreerde web-API in de externe tenant beveiligt. In deze zelfstudie bouwt u een ASP.NET Core-web-API die zowel gedelegeerde machtigingen (bereiken) als toepassingsmachtigingen (app-rollen) publiceert.
In deze zelfstudie;
- Uw web-API configureren voor het gebruik van de app-registratiegegevens
- Uw web-API configureren voor het gebruik van gedelegeerde machtigingen en toepassingsmachtigingen die zijn geregistreerd in de app-registratie
- Uw web-API-eindpunten beveiligen
Vereisten
Een API-registratie die ten minste één bereik (gedelegeerde machtigingen) en één app-rol (toepassingsmachtiging) beschikbaar maakt, zoals ToDoList.Read. Als u dat nog niet hebt gedaan, registreert u een API in het Microsoft Entra-beheercentrum door de registratiestappen te volgen. Zorg ervoor dat u het volgende hebt:
- Toepassings-id (client) van de web-API
- Map-id (tenant) van de web-API is geregistreerd
- Subdomein van de map (tenant) waar de web-API is geregistreerd. Als uw primaire domein bijvoorbeeld is contoso.onmicrosoft.com, is uw subdomein Directory (tenant) contoso.
- ToDoList.Read en ToDoList.ReadWrite als gedelegeerde machtigingen (bereiken) die beschikbaar worden gesteld door de web-API.
- ToDoList.Read.All en ToDoList.ReadWrite.All als de toepassingsmachtigingen (app-rollen) die worden weergegeven door de web-API.
.NET 7.0 SDK of hoger.
Visual Studio Code of een andere code-editor.
Een ASP.NET Core-web-API maken
Open de terminal en navigeer naar de map waarin u het project wilt opslaan.
Voer de volgende opdrachten uit:
dotnet new webapi -o ToDoListAPI cd ToDoListAPI
Wanneer u in een dialoogvenster wordt gevraagd of u vereiste assets aan het project wilt toevoegen, selecteert u Ja.
Pakketten installeren
Installeer de volgende pakketten:
Microsoft.EntityFrameworkCore.InMemory
waarmee Entity Framework Core kan worden gebruikt met een in-memory database. Het is niet ontworpen voor productiegebruik.Microsoft.Identity.Web
vereenvoudigt het toevoegen van verificatie- en autorisatieondersteuning aan web-apps en web-API's die worden geïntegreerd met het Microsoft Identity Platform.
dotnet add package Microsoft.EntityFrameworkCore.InMemory
dotnet add package Microsoft.Identity.Web
Details van app-registratie configureren
Open het appsettings.json-bestand in uw app-map en voeg de app-registratiegegevens toe die u hebt vastgelegd nadat u de web-API hebt geregistreerd.
{
"AzureAd": {
"Instance": "https://Enter_the_Tenant_Subdomain_Here.ciamlogin.com/",
"TenantId": "Enter_the_Tenant_Id_Here",
"ClientId": "Enter_the_Application_Id_Here",
},
"Logging": {...},
"AllowedHosts": "*"
}
Vervang de volgende tijdelijke aanduidingen zoals weergegeven:
- Vervang door
Enter_the_Application_Id_Here
de id van uw toepassing (client). - Vervang door
Enter_the_Tenant_Id_Here
uw map-id (tenant). - Vervang
Enter_the_Tenant_Subdomain_Here
door het subdomein Directory (tenant).
Aangepast URL-domein gebruiken (optioneel)
Gebruik een aangepast domein om de verificatie-URL volledig te merken. Vanuit gebruikersperspectief blijven gebruikers in uw domein tijdens het verificatieproces in plaats van omgeleid naar ciamlogin.com domeinnaam.
Volg deze stappen om een aangepast domein te gebruiken:
Gebruik de stappen in Aangepaste URL-domeinen inschakelen voor apps in externe tenants om aangepast URL-domein in te schakelen voor uw externe tenant.
Open appsettings.json bestand:
- Werk de waarde van de
Instance
eigenschap bij naar https://Enter_the_Custom_Domain_Here/Enter_the_Tenant_ID_Here. VervangEnter_the_Custom_Domain_Here
door uw aangepaste URL-domein enEnter_the_Tenant_ID_Here
door uw tenant-id. Als u uw tenant-id niet hebt, leest u de details van uw tenant. - Voeg
knownAuthorities
de eigenschap toe met een waarde [Enter_the_Custom_Domain_Here].
- Werk de waarde van de
Nadat u de wijzigingen in uw appsettings.json-bestand hebt aangebracht, als uw aangepaste URL-domein is login.contoso.com en uw tenant-id aaaabbbb-0000-cccc-1111-dddd2222eeeee is, moet uw bestand er ongeveer uitzien als het volgende fragment:
{
"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": "*"
}
App-rol en -bereik toevoegen
Alle API's moeten minimaal één bereik, ook wel gedelegeerde machtiging genoemd, publiceren voor de client-apps om een toegangstoken voor een gebruiker te verkrijgen. API's moeten ook minimaal één app-rol publiceren voor toepassingen, ook wel toepassingsmachtigingen genoemd, zodat de client-apps een toegangstoken kunnen verkrijgen als zichzelf, dat wil gezegd wanneer ze zich niet aanmelden bij een gebruiker.
We geven deze machtigingen op in het appsettings.json-bestand . In deze zelfstudie hebben we vier machtigingen geregistreerd. ToDoList.ReadWrite en ToDoList.Read als gedelegeerde machtigingen en ToDoList.ReadWrite.All en ToDoList.Read.All als de toepassingsmachtigingen.
{
"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": "*"
}
Verificatieschema toevoegen
Er wordt een verificatieschema genoemd wanneer de verificatieservice wordt geconfigureerd tijdens de verificatie. In dit artikel gebruiken we het JWT Bearer-verificatieschema. Voeg de volgende code toe aan het Programs.cs-bestand om een verificatieschema toe te voegen.
// 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);
Uw modellen maken
Maak een map met de naam Modellen in de hoofdmap van uw project. Navigeer naar de map en maak een bestand met de naam ToDo.cs voeg vervolgens de volgende code toe. Met deze code maakt u een model met de naam 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;
}
Een databasecontext toevoegen
De databasecontext is de belangrijkste klasse die de Functionaliteit van Entity Framework coördineert voor een gegevensmodel. Deze klasse wordt gemaakt door afgeleid van de klasse Microsoft.EntityFrameworkCore.DbContext . In deze zelfstudie gebruiken we een in-memory database voor testdoeleinden.
Maak een map met de naam DbContext in de hoofdmap van het project.
Navigeer naar die map en maak een bestand met de naam ToDoContext.cs voeg vervolgens de volgende inhoud toe aan dat bestand:
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; } }
Open het Program.cs-bestand in de hoofdmap van uw app en voeg vervolgens de volgende code toe aan het bestand. Met deze code wordt een
DbContext
subklasse geregistreerd die wordt aangeroepenToDoContext
als een scoped service in de ASP.NET Core-toepassingsserviceprovider (ook wel bekend als de container voor afhankelijkheidsinjectie). De context is geconfigureerd voor het gebruik van de in-memory database.// Add the following to your imports using ToDoListAPI.Context; using Microsoft.EntityFrameworkCore; builder.Services.AddDbContext<ToDoContext>(opt => opt.UseInMemoryDatabase("ToDos"));
Controllers toevoegen
In de meeste gevallen heeft een controller meer dan één actie. Normaal gesproken maken, lezen, bijwerken en verwijderen (CRUD) acties. In deze zelfstudie maken we slechts twee actie-items. Een actie-item lezen en een actie-item maken om te laten zien hoe u uw eindpunten beveiligt.
Navigeer naar de map Controllers in de hoofdmap van uw project.
Maak een bestand met de naam ToDoListController.cs in deze map. Open het bestand en voeg vervolgens de volgende boilerplaatcode toe:
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(){...} }
Code toevoegen aan de controller
In deze sectie voegen we code toe aan de tijdelijke aanduidingen die we hebben gemaakt. De focus hier ligt niet op het bouwen van de API, maar op het beveiligen ervan.
Importeer de benodigde pakketten. Het Microsoft.Identity.Web-pakket is een MSAL-wrapper waarmee we verificatielogica eenvoudig kunnen verwerken, bijvoorbeeld door tokenvalidatie te verwerken. Om ervoor te zorgen dat voor onze eindpunten autorisatie is vereist, gebruiken we het ingebouwde Microsoft.AspNetCore.Authorization-pakket .
Omdat we machtigingen hebben verleend voor deze API die moet worden aangeroepen met gedelegeerde machtigingen namens de gebruiker of toepassingsmachtigingen waarbij de client zichzelf aanroept en niet namens de gebruiker, is het belangrijk om te weten of de aanroep door de app zelf wordt gedaan. De eenvoudigste manier om dit te doen, is de claims om te bepalen of het toegangstoken de
idtyp
optionele claim bevat. Dezeidtyp
claim is de eenvoudigste manier voor de API om te bepalen of een token een app-token is of een app + gebruikerstoken. U wordt aangeraden deidtyp
optionele claim in te schakelen.Als de
idtyp
claim niet is ingeschakeld, kunt u deroles
enscp
claims gebruiken om te bepalen of het toegangstoken een app-token of een app + gebruikerstoken is. Een toegangstoken dat is uitgegeven door Microsoft Entra Externe ID heeft ten minste één van de twee claims. Toegangstokens die zijn uitgegeven aan een gebruiker, hebben descp
claim. Toegangstokens die zijn uitgegeven aan een toepassing, hebben deroles
claim. Toegangstokens die beide claims bevatten, worden alleen verleend aan gebruikers, waarbij descp
claim de gedelegeerde machtigingen aanwijst, terwijl deroles
claim de rol van de gebruiker aanwijst. Toegangstokens die geen van beide moeten worden gehonoreerd.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"); } }
Voeg een helperfunctie toe die bepaalt of de aanvraag die wordt gedaan voldoende machtigingen bevat om de beoogde actie uit te voeren. Controleer of de app de aanvraag zelf indient of dat de app de aanroep doet namens een gebruiker die eigenaar is van de opgegeven resource door de gebruikers-id te valideren.
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; }
Sluit uw machtigingsdefinities aan om routes te beveiligen. Beveilig uw API door het
[Authorize]
kenmerk toe te voegen aan de controllerklasse. Dit zorgt ervoor dat de controlleracties alleen kunnen worden aangeroepen als de API wordt aangeroepen met een geautoriseerde identiteit. De machtigingsdefinities definiëren welke soorten machtigingen nodig zijn om deze acties uit te voeren.[Authorize] [Route("api/[controller]")] [ApiController] public class ToDoListController: ControllerBase{...}
Voeg machtigingen toe aan het GET-eindpunt en het POST-eindpunt. Gebruik hiervoor de methode RequiredScopeOrAppPermission die deel uitmaakt van de naamruimte Microsoft.Identity.Web.Resource . Vervolgens geeft u bereiken en machtigingen door aan deze methode via de kenmerken RequiredScopesConfigurationKey en 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); }
Uw API uitvoeren
Voer uw API uit om ervoor te zorgen dat deze goed wordt uitgevoerd zonder fouten met behulp van de opdracht dotnet run
. Als u het HTTPS-protocol zelfs tijdens het testen wilt gebruiken, moet u vertrouwen. Het ontwikkelingscertificaat van NET.
Zie het voorbeeldbestand voor een volledig voorbeeld van deze API-code.