Cvičení – použití deklarací identity s autorizací na základě zásad
V této lekci vytvoříte nového uživatele s oprávněními správce. Její součástí je ukázka vytvoření a uložení deklarací identity uživatelů. Zároveň jsou definované zásady autorizace, aby bylo možné určit, jestli má ověřený uživatel zvýšená oprávnění v uživatelském rozhraní.
Zabezpečení katalogu produktů
Stránka katalogu produktů by měla být viditelná jen ověřeným uživatelům. Produkty ale mohou upravovat, vytvářet a odstraňovat jen správci.
V souboru Pages/Products/Index.cshtml.cs proveďte následující změny:
Nahraďte komentář
// Add [Authorize] attributenásledujícím atributem:[Authorize]Předchozí atribut popisuje požadavky na ověření uživatele pro tuto stránku. V tomto případě neexistují kromě ověření uživatele žádné požadavky. Anonymní uživatelé nemohou tuto stránku zobrazit a jsou přesměrováni na přihlašovací stránku.
Zrušte komentář u řádku
//using Microsoft.AspNetCore.Authorization;na začátku souboru.Předchozí změna přeloží atribut
[Authorize]v předchozím kroku.Nahraďte komentář
// Add IsAdmin propertynásledující vlastností:public bool IsAdmin => HttpContext.User.HasClaim("IsAdmin", bool.TrueString);Předchozí kód určuje, jestli má ověřený uživatel deklaraci identity
IsAdmins hodnotouTrue. Výsledek tohoto vyhodnocení je přístupný přes vlastnost jen pro čtení s názvemIsAdmin.Nahraďte komentář
// Add IsAdmin checkv metoděOnDeletenásledujícím kódem:if (!IsAdmin) { return Forbid(); }Když se ověřený zaměstnanec pokusí odstranit produkt přes uživatelské rozhraní nebo ruční odeslání žádosti HTTP DELETE této stránce, vrátí se stavový kód HTTP 403.
V souboru Pages/Products/Index.cshtml aktualizujte odkazy pro úpravu, odstranění a přidání produktu následujícím zvýrazněným kódem:
Odkazy pro úpravu a odstranění:
<td> @if (Model.IsAdmin) { <a asp-page="Edit" asp-route-id="@product.Id">Edit</a> <span>|</span> <a href="#" onclick="deleteProduct('@product.Id', antiForgeryToken())">Delete</a> } </td>Odkaz pro přidání produktu:
@if (Model.IsAdmin) { <a asp-page="./Create">Add Product</a> }Předchozí změny způsobí, že se tyto odkazy vykreslí jen v případě, že je ověřeným uživatelem správce.
Registrace a uplatnění zásad autorizace
Stránky pro vytvoření produktu a úpravu produktu by měly být přístupné jen správcům. Pro zapouzdření autorizačních kritérií pro tyto stránky se vytvoří zásady Admin.
V metodě
ConfigureServicesv souboru Startup.cs proveďte následující změny:Nahraďte komentář
// Add call to AddAuthorizationnásledujícím kódem:services.AddAuthorization(options => options.AddPolicy("Admin", policy => policy.RequireAuthenticatedUser() .RequireClaim("IsAdmin", bool.TrueString)));Předchozí kód definuje zásady autorizace s názvem
Admin. Tyto zásady vyžadují, aby byl uživatel ověřený a deklaraci identityIsAdminměl nastavenou naTrue.Začleňte následující zvýrazněný kód:
services.AddAntiforgery(options => options.HeaderName = "X-CSRF-TOKEN"); services.AddRazorPages(options => options.Conventions.AuthorizePage("/Products/Edit", "Admin")); services.AddControllers();Volání metody
AuthorizePagezabezpečí směrování stránky Razor /Products/Edit uplatněním zásadAdmin. Výhodou tohoto přístupu je, že tato zabezpečovaná stránka Razor nevyžaduje žádné úpravy. Aspekt autorizace se místo toho spravuje v souboru Startup.cs. Anonymní uživatelé budou přesměrováni na přihlašovací stránku. Ověřeným uživatelům, kteří nesplňují požadavky zásad, se zobrazí zpráva o odepření přístupu.
V souboru Pages/Products/Create.cshtml.cs proveďte následující změny:
Nahraďte komentář
// Add [Authorize(Policy = "Admin")] attributenásledujícím atributem:[Authorize(Policy = "Admin")]Předchozí kód představuje alternativu k volání metody
AuthorizePagev souboru Startup.cs. Atribut[Authorize]vynucuje, aby požadavky zásadAdminbyly splněny. Anonymní uživatelé budou přesměrováni na přihlašovací stránku. Ověřeným uživatelům, kteří nesplňují požadavky zásad, se zobrazí zpráva o odepření přístupu.Zrušte komentář u řádku
//using Microsoft.AspNetCore.Authorization;na začátku souboru.Předchozí změna přeloží atribut
[Authorize(Policy = "Admin")]v předchozím kroku.
Úprava registrační stránky
Následujícím postupem upravte registrační stránku tak, abyste správcům umožnili registraci.
V souboru Areas/Identity/Pages/Account/Register.cshtml.cs proveďte následující změny:
Do vnořené třídy
InputModelpřidejte následující vlastnost:public class InputModel { [DataType(DataType.Password)] [Display(Name = "Admin enrollment key")] public ulong? AdminEnrollmentKey { get; set; } [Required] [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 1)] [Display(Name = "First name")] public string FirstName { get; set; } [Required] [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 1)] [Display(Name = "Last name")] public string LastName { get; set; } [Required] [EmailAddress] [Display(Name = "Email")] public string Email { get; set; } [Required] [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)] [DataType(DataType.Password)] [Display(Name = "Password")] public string Password { get; set; } [DataType(DataType.Password)] [Display(Name = "Confirm password")] [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] public string ConfirmPassword { get; set; } }Do metody
OnPostAsynczačleňte zvýrazněné změny:public async Task<IActionResult> OnPostAsync( [FromServices] AdminRegistrationTokenService tokenService, string returnUrl = null) { returnUrl = returnUrl ?? Url.Content("~/"); ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList(); if (ModelState.IsValid) { var user = new ContosoPetsUser { FirstName = Input.FirstName, LastName = Input.LastName, UserName = Input.Email, Email = Input.Email, }; var result = await _userManager.CreateAsync(user, Input.Password); if (result.Succeeded) { _logger.LogInformation("User created a new account with password."); await _userManager.AddClaimAsync(user, new Claim("IsAdmin", (Input.AdminEnrollmentKey == tokenService.CreationKey).ToString())); var code = await _userManager.GenerateEmailConfirmationTokenAsync(user); code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code)); var callbackUrl = Url.Page( "/Account/ConfirmEmail", pageHandler: null, values: new { area = "Identity", userId = user.Id, code = code }, protocol: Request.Scheme); await _emailSender.SendEmailAsync(Input.Email, "Confirm your email", $"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>."); if (_userManager.Options.SignIn.RequireConfirmedAccount) { return RedirectToPage("RegisterConfirmation", new { email = Input.Email }); } else { await _signInManager.SignInAsync(user, isPersistent: false); return LocalRedirect(returnUrl); } } foreach (var error in result.Errors) { ModelState.AddModelError(string.Empty, error.Description); } } // If we got this far, something failed, redisplay form return Page(); }V předchozím kódu:
- Atribut
[FromServices]poskytuje instanciAdminRegistrationTokenServicez kontejneru IOC. - Metoda
AddClaimAsynctřídyUserManagerje vyvolána za účelem uložení deklarace identityIsAdmindo tabulkyAspNetUserClaims.
- Atribut
Na začátek souboru přidejte následující kód. Tento kód překládá odkazy na třídu
AdminRegistrationTokenServiceaClaimv metoděOnPostAsync:using ContosoPets.Ui.Services; using System.Security.Claims;
Do souboru Areas/Identity/Pages/Account/Register.cshtml přidejte následující kód:
<div class="form-group"> <label asp-for="Input.ConfirmPassword"></label> <input asp-for="Input.ConfirmPassword" class="form-control" /> <span asp-validation-for="Input.ConfirmPassword" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="Input.AdminEnrollmentKey"></label> <input asp-for="Input.AdminEnrollmentKey" class="form-control" /> <span asp-validation-for="Input.AdminEnrollmentKey" class="text-danger"></span> </div> <button type="submit" class="btn btn-primary">Register</button>
Otestování deklarace identity správce
Spuštěním následujícího příkazu sestavte aplikaci:
dotnet build --no-restoreParametr
--no-restoreje použitý, protože od posledního sestavení nebyly přidány žádné balíčky NuGet. Proces sestavení vynechá obnovení balíčků NuGet a úspěšně se dokončí bez upozornění. Pokud se sestavení nezdaří, zkontrolujte výstupní informace o odstraňování potíží.Spuštěním následujícího příkazu nasaďte aplikaci do Azure App Service:
az webapp upPřejděte do aplikace a přihlaste se jako existující uživatel, pokud ještě nejste přihlášeni. V záhlaví vyberte produkty. Všimněte si, že tomuto uživateli se nezobrazují odkazy pro úpravy, odstranění nebo vytvoření produktů.
V adresním řádku prohlížeče přejděte přímo na stránku pro vytvoření produktu. Adresu URL této stránky lze získat spuštěním následujícího příkazu:
echo "$webAppUrl/Products/Create"Tomuto uživateli je zakázán přechod na tuto stránku. Zobrazí se zpráva o odepření přístupu. Tento uživatel bude mít podobně zakázaný přechod například sem: /Products/Edit/1.
Vyberte možnost odhlášení.
Pomocí následujícího příkazu si opatřete token pro samoobslužnou registraci správce:
echo $(wget -q -O - $webAppUrl/admintoken)Upozornění
Mechanismus samoobslužné registrace správce je uvedený jen pro ilustrativní účely. Koncový bod /api/Admin pro získání tokenu by měl být před použitím v produkčním prostředí zabezpečen.
Ve webové aplikaci zaregistrujte nového uživatele. Token z předchozího kroku by měl být zadán do textového pole pro registrační klíč správce.
Jakmile se přihlásíte jako nový správce, klikněte v záhlaví na odkaz na produkty.
Správce může prohlížet, upravovat a vytvářet produkty.
Prohlídka tabulky AspNetUserClaims
Spusťte následující příkaz:
db -c 'SELECT u."Email", c."ClaimType", c."ClaimValue" FROM "AspNetUserClaims" AS c INNER JOIN "AspNetUsers" AS u ON c."UserId" = u."Id"'
Zobrazí se varianta následujícího výstupu:
Email | ClaimType | ClaimValue
----------------------+-----------+------------
scott@contoso.com | IsAdmin | True
(1 row)
db -Q "SELECT u.Email, c.ClaimType, c.ClaimValue FROM dbo.AspNetUserClaims AS c INNER JOIN dbo.AspNetUsers AS u ON c.UserId = u.Id" -Y25 -y10
Zobrazí se varianta následujícího výstupu:
Email ClaimType ClaimValue
------------------------- ---------- ----------
scott@contoso.com IsAdmin True
Deklarace identity IsAdmin je uložená v tabulce AspNetUserClaims jako dvojice klíč-hodnota. Záznam AspNetUserClaims je přidružený k záznamu uživatele v tabulce AspNetUsers.
Potřebujete pomoc? Projděte si našeho průvodce odstraňováním potíží nebo nahlaste potíže a uveďte konkrétní připomínky.