Oefening: claims gebruiken met op beleid gebaseerde autorisatie
In de vorige les hebt u het verschil tussen verificatie en autorisatie geleerd. U hebt ook geleerd hoe claims worden gebruikt door beleid voor autorisatie. In deze eenheid gebruikt u Identiteit voor het opslaan van claims en het toepassen van beleid voor voorwaardelijke toegang.
De pizzalijst beveiligen
U hebt een nieuwe vereiste ontvangen dat de pagina Pizzalijst alleen zichtbaar moet zijn voor geverifieerde gebruikers. Daarnaast mogen alleen beheerders pizza's maken en verwijderen. Laten we het vergrendelen.
Pas in Pagina's/Pizza.cshtml.cs de volgende wijzigingen toe:
Voeg een
[Authorize]
kenmerk toe aan dePizzaModel
klasse.[Authorize] public class PizzaModel : PageModel
Het kenmerk beschrijft de vereisten voor gebruikersautorisatie voor de pagina. In dit geval is de enige vereiste dat de gebruiker moet worden geverifieerd. Anonieme gebruikers mogen de pagina niet bekijken en worden omgeleid naar de aanmeldingspagina.
Los de verwijzing naar
Authorize
op door de volgende regel toe te voegen aan deusing
instructies boven aan het bestand:using Microsoft.AspNetCore.Authorization;
Voeg de volgende eigenschap toe aan de klasse
PizzaModel
:[Authorize] public class PizzaModel : PageModel { public bool IsAdmin => HttpContext.User.HasClaim("IsAdmin", bool.TrueString); public List<Pizza> pizzas = new();
De voorgaande code bepaalt of de geverifieerde gebruiker een
IsAdmin
-claim met waardeTrue
heeft. De code haalt informatie op over de geverifieerde gebruiker van deHttpContext
bovenliggendePageModel
klasse. Het resultaat van deze evaluatie is toegankelijk via een eigenschap alleen-lezen met de naamIsAdmin
.Toevoegen
if (!IsAdmin) return Forbid();
aan het begin van zowel de alsOnPost
deOnPostDelete
methoden:public IActionResult OnPost() { if (!IsAdmin) return Forbid(); if (!ModelState.IsValid) { return Page(); } PizzaService.Add(NewPizza); return RedirectToAction("Get"); } public IActionResult OnPostDelete(int id) { if (!IsAdmin) return Forbid(); PizzaService.Delete(id); return RedirectToAction("Get"); }
In de volgende stap verbergt u de elementen van de gebruikersinterface voor het maken/verwijderen van gebruikersinterfaces voor niet-beheerders. Dat voorkomt niet dat een kwaadwillende persoon met een hulpprogramma, zoals HttpRepl of curl, rechtstreeks toegang krijgt tot deze eindpunten. Als u deze controle toevoegt, zorgt u ervoor dat als dit wordt geprobeerd, een HTTP 403-statuscode wordt geretourneerd.
Voeg in Pages/Pizza.cshtml controles toe om ui-elementen van beheerders te verbergen voor niet-beheerders:
Nieuw pizzaformulier verbergen
<h1>Pizza List 🍕</h1> @if (Model.IsAdmin) { <form method="post" class="card p-3"> <div class="row"> <div asp-validation-summary="All"></div> </div> <div class="form-group mb-0 align-middle"> <label asp-for="NewPizza.Name">Name</label> <input type="text" asp-for="NewPizza.Name" class="mr-5"> <label asp-for="NewPizza.Size">Size</label> <select asp-for="NewPizza.Size" asp-items="Html.GetEnumSelectList<PizzaSize>()" class="mr-5"></select> <label asp-for="NewPizza.Price"></label> <input asp-for="NewPizza.Price" class="mr-5" /> <label asp-for="NewPizza.IsGlutenFree">Gluten Free</label> <input type="checkbox" asp-for="NewPizza.IsGlutenFree" class="mr-5"> <button class="btn btn-primary">Add</button> </div> </form> }
Knop Pizza verwijderen verbergen
<table class="table mt-5"> <thead> <tr> <th scope="col">Name</th> <th scope="col">Price</th> <th scope="col">Size</th> <th scope="col">Gluten Free</th> @if (Model.IsAdmin) { <th scope="col">Delete</th> } </tr> </thead> @foreach (var pizza in Model.pizzas) { <tr> <td>@pizza.Name</td> <td>@($"{pizza.Price:C}")</td> <td>@pizza.Size</td> <td>@Model.GlutenFreeText(pizza)</td> @if (Model.IsAdmin) { <td> <form method="post" asp-page-handler="Delete" asp-route-id="@pizza.Id"> <button class="btn btn-danger">Delete</button> </form> </td> } </tr> } </table>
De voorgaande wijzigingen zorgen ervoor dat ui-elementen die alleen toegankelijk moeten zijn voor beheerders alleen worden weergegeven wanneer de geverifieerde gebruiker een beheerder is.
Een autorisatiebeleid toepassen
Er is nog één ding dat je moet vergrendelen. Er is een pagina die alleen toegankelijk moet zijn voor beheerders, met de naam Pages/AdminsOnly.cshtml. Laten we een beleid maken om de IsAdmin=True
claim te controleren.
Breng in Program.cs de volgende wijzigingen aan:
Neem de volgende gemarkeerde code op:
// Add services to the container. builder.Services.AddRazorPages(); builder.Services.AddTransient<IEmailSender, EmailSender>(); builder.Services.AddSingleton(new QRCodeService(new QRCodeGenerator())); builder.Services.AddAuthorization(options => options.AddPolicy("Admin", policy => policy.RequireAuthenticatedUser() .RequireClaim("IsAdmin", bool.TrueString))); var app = builder.Build();
Met de voorgaande code wordt autorisatiebeleid met de naam
Admin
gemaakt. Het beleid vereist dat de gebruiker is geverifieerd en dat er eenIsAdmin
-claim is ingesteld voorTrue
.Wijzig de aanroep als
AddRazorPages
volgt:builder.Services.AddRazorPages(options => options.Conventions.AuthorizePage("/AdminsOnly", "Admin"));
De
AuthorizePage
methodeaanroep beveiligt de route /AdminsOnly Razor Page door hetAdmin
beleid toe te passen. Geverifieerde gebruikers die niet voldoen aan de beleidsvereisten, krijgen een Toegang geweigerd-bericht.Tip
U kunt in plaats daarvan ook AdminsOnly.cshtml.cs wijzigen. In dat geval voegt u dit toe
[Authorize(Policy = "Admin")]
als een kenmerk in deAdminsOnlyModel
klasse. Een voordeel van deAuthorizePage
hierboven weergegeven benadering is dat de Razor-pagina die wordt beveiligd, geen wijzigingen vereist. Het autorisatie-aspect wordt in plaats daarvan beheerd in Program.cs.
Neem in Pages/Shared/_Layout.cshtml de volgende wijzigingen op:
<ul class="navbar-nav flex-grow-1"> <li class="nav-item"> <a class="nav-link text-dark" asp-area="" asp-page="/Index">Home</a> </li> <li class="nav-item"> <a class="nav-link text-dark" asp-area="" asp-page="/Pizza">Pizza List</a> </li> <li class="nav-item"> <a class="nav-link text-dark" asp-area="" asp-page="/Privacy">Privacy</a> </li> @if (Context.User.HasClaim("IsAdmin", bool.TrueString)) { <li class="nav-item"> <a class="nav-link text-dark" asp-area="" asp-page="/AdminsOnly">Admins</a> </li> } </ul>
Met de voorgaande wijziging wordt de koppeling Beheerder in de koptekst voorwaardelijk verborgen als de gebruiker geen beheerder is. De eigenschap van de
Context
klasse wordt gebruiktRazorPage
voor toegang tot deHttpContext
informatie over de geverifieerde gebruiker.
De IsAdmin
claim toevoegen aan een gebruiker
Om te bepalen welke gebruikers de IsAdmin=True
claim moeten ontvangen, gaat uw app vertrouwen op een bevestigd e-mailadres om de beheerder te identificeren.
Voeg in appsettings.json de gemarkeerde eigenschap toe:
{ "AdminEmail" : "admin@contosopizza.com", "Logging": {
Dit is het bevestigd e-mailadres dat de claim krijgt toegewezen.
Breng in gebieden/identiteit/pagina's/account/ConfirmEmail.cshtml.cs de volgende wijzigingen aan:
Neem de volgende gemarkeerde code op:
public class ConfirmEmailModel : PageModel { private readonly UserManager<RazorPagesPizzaUser> _userManager; private readonly IConfiguration Configuration; public ConfirmEmailModel(UserManager<RazorPagesPizzaUser> userManager, IConfiguration configuration) { _userManager = userManager; Configuration = configuration; }
De voorgaande wijziging wijzigt de constructor om een
IConfiguration
van de IoC-container te ontvangen. DeIConfiguration
bevat waarden uit appsettings.json en wordt toegewezen aan een alleen-lezen eigenschap met de naamConfiguration
.Pas de gemarkeerde wijzigingen toe op de methode
OnGetAsync
:public async Task<IActionResult> OnGetAsync(string userId, string code) { if (userId == null || code == null) { return RedirectToPage("/Index"); } var user = await _userManager.FindByIdAsync(userId); if (user == null) { return NotFound($"Unable to load user with ID '{userId}'."); } code = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(code)); var result = await _userManager.ConfirmEmailAsync(user, code); StatusMessage = result.Succeeded ? "Thank you for confirming your email." : "Error confirming your email."; var adminEmail = Configuration["AdminEmail"] ?? string.Empty; if(result.Succeeded) { var isAdmin = string.Compare(user.Email, adminEmail, true) == 0 ? true : false; await _userManager.AddClaimAsync(user, new Claim("IsAdmin", isAdmin.ToString())); } return Page(); }
In de voorgaande code:
- De
AdminEmail
tekenreeks wordt gelezen uit deConfiguration
eigenschap en toegewezen aanadminEmail
. - De operator
??
null-coalescing wordt gebruikt om ervoor te zorgen datadminEmail
deze is ingesteldstring.Empty
op als er geen overeenkomstige waarde in appsettings.json is. - Als het e-mailadres van de gebruiker is bevestigd:
- Het adres van de gebruiker wordt vergeleken met
adminEmail
.string.Compare()
wordt gebruikt voor een niet-hoofdlettergevoelige vergelijking. - De methode
UserManager
van de klasseAddClaimAsync
wordt aangeroepen om eenIsAdmin
-claim in de tabelAspNetUserClaims
op te slaan.
- Het adres van de gebruiker wordt vergeleken met
- De
Voeg de volgende code boven in het bestand toe. Hiermee worden de
Claim
klasseverwijzingen in deOnGetAsync
methode omgezet:using System.Security.Claims;
De beheerdersclaim testen
Laten we een laatste test uitvoeren om de nieuwe beheerdersfunctionaliteit te controleren.
Zorg ervoor dat u al uw wijzigingen hebt opgeslagen.
Voer de app uit met
dotnet run
.Navigeer naar uw app en meld u aan met een bestaande gebruiker als u nog niet bent aangemeld. Selecteer Pizzalijst in de koptekst. U ziet dat de gebruiker geen UI-elementen bevat om pizza's te verwijderen of te maken.
Er is geen koppeling beheerders in de koptekst. Navigeer in de adresbalk van de browser rechtstreeks naar de pagina AdminsOnly . Vervang
/Pizza
in de URL door/AdminsOnly
.Het is de gebruiker verboden om naar de pagina te navigeren. Er wordt een Toegang geweigerd-bericht weergegeven.
Selecteer Afmelden.
Registreer een nieuwe gebruiker met het adres
admin@contosopizza.com
.Bevestig net als voorheen het e-mailadres van de nieuwe gebruiker en meld u aan.
Nadat u zich hebt aangemeld met de nieuwe gebruiker met beheerdersrechten, selecteert u de koppeling pizzalijst in de koptekst.
De gebruiker met beheerdersrechten kan pizza's maken en verwijderen.
Selecteer de koppeling Beheerders in de koptekst.
De pagina AdminsOnly wordt weergegeven.
De tabel AspNetUserClaims controleren
Voer met behulp van de SQL Server-extensie in VS Code de volgende query uit:
SELECT u.Email, c.ClaimType, c.ClaimValue
FROM dbo.AspNetUserClaims AS c
INNER JOIN dbo.AspNetUsers AS u
ON c.UserId = u.Id
Er wordt een tabblad met resultaten weergegeven die er ongeveer als volgt uitzien:
E-mailen | ClaimType | ClaimValue |
---|---|---|
admin@contosopizza.com | IsAdmin | Waar |
De claim IsAdmin
wordt opgeslagen als een sleutel-waardepaar in de tabel AspNetUserClaims
. Het record AspNetUserClaims
is gekoppeld aan het gebruikersrecord in de tabel AspNetUsers
.
Samenvatting
In deze les hebt u de app gewijzigd om claims op te slaan en beleidsregels toe te passen voor voorwaardelijke toegang.