Alıştırma - İlke tabanlı yetkilendirme ile talepleri kullanma
Bu ünitede, yönetici ayrıcalıklarına sahip yeni bir kullanıcı oluşturacaksınız. Kullanıcı taleplerini oluşturmayı ve depolamayı gösteren bir tanıtım sunulmuştur. Kimliği doğrulanmış bir kullanıcının kullanıcı arabiriminde yükseltilmiş ayrıcalıklara sahip olup olmayacağını belirlemek için bir yetkilendirme ilkesi de tanımlanır.
Ürün kataloglarını güvenli hale getirme
Ürün kataloğu sayfası yalnızca kimliği doğrulanmış kullanıcılar için görünür olmalıdır. Ancak, ürünleri yalnızca yöneticilerin düzenlemesine, oluşturmasına ve silmesine izin verilir.
Pages/Products/Index.cshtml.cs dosyasında aşağıdaki değişiklikleri uygulayın:
// Add [Authorize] attributeaçıklamasını aşağıdaki öznitelik ile değiştirin:[Authorize]Yukarıdaki öznitelik, sayfaya yönelik kullanıcı kimlik doğrulaması gereksinimlerini açıklar. Bu durumda, kullanıcının kimliğinin doğrulanması dışında başka bir gereksinim yoktur. Anonim kullanıcıların sayfayı görüntülemesine izin verilmez ve bu kullanıcılar, oturum açma sayfasına yeniden yönlendirilir.
Dosyanın en üstündeki
//using Microsoft.AspNetCore.Authorization;satırının açıklamasını kaldırın.Yukarıdaki değişiklik, önceki adımdaki
[Authorize]özniteliğini çözümler.// Add IsAdmin propertyaçıklamasını aşağıdaki özellik ile değiştirin:public bool IsAdmin => HttpContext.User.HasClaim("IsAdmin", bool.TrueString);Yukarıdaki kod, kimliği doğrulanmış kullanıcının
Truedeğerine sahip birIsAdmintalebinin olup olmadığını belirler. Bu değerlendirmenin sonuçlarına,IsAdminadlı bir salt okunur özellik aracılığıyla erişilir.OnDeletemetodundaki// Add IsAdmin checkaçıklamasını aşağıdaki kodla değiştirin:if (!IsAdmin) { return Forbid(); }Kimliği doğrulanmış bir çalışan, kullanıcı arabirimi aracılığıyla veya bu sayfaya bir HTTP DELETE isteği göndererek bir ürünü silmeye çalışırsa HTTP 403 durum kodu döndürülür.
Pages/Products/Index.cshtml dosyasında, Düzenle, Sil ve Ürün Ekle bağlantılarını vurgulanmış kod ile güncelleştirin:
Düzenle ve Sil Bağlantıları:
<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>Ürün Ekle Bağlantısı:
@if (Model.IsAdmin) { <a asp-page="./Create">Add Product</a> }Yukarıdaki değişiklikler, bağlantıların yalnızca kimliği doğrulanan kullanıcının bir yönetici olduğu durumlarda işlenmesine neden olur.
Yetkilendirme ilkesini kaydetme ve uygulama
Ürün Oluşturma ve Ürün Düzenleme sayfaları yalnızca yöneticiler için erişilebilir olmalıdır. Bu sayfalara yönelik yetkilendirme kriterlerini kapsüllemek için bir Admin ilkesi oluşturulur.
Startup.cs dosyasının
ConfigureServicesmetodunda aşağıdaki değişiklikleri yapın:// Add call to AddAuthorizationaçıklamasını aşağıdaki kodla değiştirin:services.AddAuthorization(options => options.AddPolicy("Admin", policy => policy.RequireAuthenticatedUser() .RequireClaim("IsAdmin", bool.TrueString)));Yukarıdaki kod,
Adminadlı bir yetkilendirme ilkesi tanımlar. İlke, kullanıcının kimliğinin doğrulanmasını veTrueolarak ayarlı birIsAdmintalebinin olmasını gerektirir.Aşağıdaki vurgulanmış kodu ekleyin:
services.AddAntiforgery(options => options.HeaderName = "X-CSRF-TOKEN"); services.AddRazorPages(options => options.Conventions.AuthorizePage("/Products/Edit", "Admin")); services.AddControllers();AuthorizePagemetot çağrısı,Adminilkesini uygulayarak /Products/Edit Razor sayfası yolunu güvenli hale getirir. Bu yaklaşımın sunduğu avantajların biri de, güvenli hale getirilen Razor sayfasının değişiklik gerektirmemesidir. Bunun yerine, yetkilendirme özelliği Startup.cs dosyasında yönetilir. Anonim kullanıcılar oturum açma sayfasına yönlendirilir. İlke gereksinimlerini karşılamayan kimliği doğrulanmış kullanıcılara bir Erişim reddedildi iletisi gösterilir.
Pages/Products/Create.cshtml.cs dosyasında aşağıdaki değişiklikleri uygulayın:
// Add [Authorize(Policy = "Admin")] attributeaçıklamasını aşağıdaki öznitelik ile değiştirin:[Authorize(Policy = "Admin")]Yukarıdaki kod, Startup.cs dosyasındaki
AuthorizePagemetot çağrısı için bir alternatif sunar.[Authorize]özniteliği,Adminilke gereksinimlerinin karşılanmasını sağlar. Anonim kullanıcılar oturum açma sayfasına yönlendirilir. İlke gereksinimlerini karşılamayan kimliği doğrulanmış kullanıcılara bir Erişim reddedildi iletisi gösterilir.Dosyanın en üstündeki
//using Microsoft.AspNetCore.Authorization;satırının açıklamasını kaldırın.Yukarıdaki değişiklik, önceki adımdaki
[Authorize(Policy = "Admin")]özniteliğini çözümler.
Kayıt sayfasını değiştirme
Yöneticilerin aşağıdaki adımları kullanarak kaydolmasına izin vermek için kayıt sayfasını değiştirin.
Areas/Identity/Pages/Account/Register.cshtml.cs dosyasında aşağıdaki değişiklikleri yapın:
İç içe geçmiş
InputModelsınıfına aşağıdaki özelliği ekleyin: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; } }Vurgulanan değişiklikleri
OnPostAsyncmetoduna uygulayın: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(); }Yukarıdaki kodda:
[FromServices]özniteliği, IoC kapsayıcısındanAdminRegistrationTokenServiceöğesinin bir örneğini sağlar.AspNetUserClaimstablosundakiIsAdmintalebini kaydetmek içinUserManagersınıfınınAddClaimAsyncmetodu çağrılır.
Aşağıdaki kodu dosyanın en üstüne ekleyin.
OnPostAsyncmetodundakiAdminRegistrationTokenServiceveClaimsınıf başvurularını çözümler:using ContosoPets.Ui.Services; using System.Security.Claims;
Areas/Identity/Pages/Account/Register.cshtml dosyasına aşağıdaki işaretlemeyi ekleyin:
<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>
Yönetici talebini test etme
Uygulamayı derlemek için aşağıdaki komutu çalıştırın:
dotnet build --no-restoreSon derlemeden sonra NuGet paketi eklenmediğinden
--no-restoreseçeneği de eklenmiştir. Derleme işlemi, NuGet paketlerinin geri yüklenmesini atlar ve uyarı oluşturmadan başarıyla tamamlanır. Derleme başarısız olursa, sorun giderme bilgileri için çıkışı inceleyin.Aşağıdaki komutu çalıştırarak uygulamayı Azure App Service’e dağıtın:
az webapp upZaten oturum açmadıysanız, uygulamanıza gidip mevcut bir kullanıcı ile oturum açın. Üst bilgiden Ürünler’i seçin. Kullanıcıya, ürünleri düzenlemek, silmek veya oluşturmak için bağlantı sunulmadığına dikkat edin.
Tarayıcının adres çubuğunu kullanarak doğrudan Ürün Oluştur sayfasına gidin. Sayfanın URL’si aşağıdaki komut çalıştırılarak elde edilebilir:
echo "$webAppUrl/Products/Create"Kullanıcının bu sayfaya gitmesi yasaktır. Erişim engellendi iletisi görüntülenir. Benzer şekilde, kullanıcının /Products/Edit/1 yolu gibi bir yola gitmesi de yasaktır.
Oturumu Kapat’ı seçin.
Aşağıdaki komutu kullanarak yöneticilere yönelik bir kendi kendine kaydolma belirteci edinin:
echo $(wget -q -O - $webAppUrl/admintoken)Uyarı
Yöneticilere yönelik kendi kendine kaydolma mekanizması yalnızca açıklayıcı nitelik taşır. Belirteç edinmeye yönelik /api/Admin uç noktası, bir üretim ortamında kullanılmadan önce güvenli hale getirilmelidir.
Web uygulamasında yeni bir kullanıcı kaydedin. Önceki adımdaki belirteç, Yönetici kayıt anahtarı metin kutusunda sağlanmalıdır.
Yeni yönetici kullanıcı ile oturum açtıktan sonra, üst bilgideki Ürünler bağlantısına tıklayın.
Yönetim kullanıcısı ürünleri görüntüleyebilir, düzenleyebilir ve oluşturabilir.
AspNetUserClaims tablosunu inceleme
Şu komutu çalıştırın:
db -c 'SELECT u."Email", c."ClaimType", c."ClaimValue" FROM "AspNetUserClaims" AS c INNER JOIN "AspNetUsers" AS u ON c."UserId" = u."Id"'
Aşağıdaki çıkışın bir varyasyonu görüntülenir:
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
Aşağıdaki çıkışın bir varyasyonu görüntülenir:
Email ClaimType ClaimValue
------------------------- ---------- ----------
scott@contoso.com IsAdmin True
IsAdmin talebi, AspNetUserClaims tablosunda anahtar-değer çifti olarak depolanır. AspNetUserClaims kaydı, AspNetUsers tablosundaki kullanıcı kaydıyla ilişkilendirilir.
Yardıma mı ihtiyacınız var? Sorun giderme kılavuzumuza gözatın veya sorun bildirerek belirli bir konuda geri bildiriminizi paylaşın.