Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Tarafından Rick Anderson ve Joe Audette
Bu öğreticide, yetkilendirmeyle korunan kullanıcı verileriyle bir ASP.NET Core web uygulamasının nasıl oluşturulacağı gösterilmektedir. Kimliği doğrulanmış (kayıtlı) kullanıcıların oluşturduğu kişilerin listesini görüntüler. Üç güvenlik grubu vardır:
- Kayıtlı kullanıcılar onaylanan tüm verileri görüntüleyebilir ve kendi verilerini düzenleyebilir/silebilir.
- Yöneticiler iletişim verilerini onaylayabilir veya reddedebilir. Yalnızca onaylanan kişiler kullanıcılar tarafından görülebilir.
- Yöneticiler tüm verileri onaylayabilir/reddedebilir ve düzenleyebilir/silebilir.
Bu belgedeki resimler en son şablonlarla tam olarak eşleşmiyor.
Aşağıdaki görüntüde Rick () kullanıcısı oturum açmış. Rick yalnızca onaylanan kişileri görüntüleyebilir ve kişileri için Düzenle, Sil, Yeni Oluştur bağlantılarını görebilir. Yalnızca Rick tarafından oluşturulan son kayıt Düzenle ve Sil bağlantılarını görüntüler. Yönetici veya yönetici durumu "Onaylandı" olarak değiştirene kadar diğer kullanıcılar son kaydı görmez.
Rick'in oturum açtığını gösteren ekran görüntüsü
Aşağıdaki görüntüde, yöneticinin rolünde oturum açmıştır:
Oturum açtığını gösteren ekran görüntüsü
Aşağıdaki görüntüde, bir kişinin yönetici ayrıntıları görünümü gösterilmektedir:
Yöneticinin kontak görüşü
Onayla ve Reddet düğmeleri yalnızca yöneticiler ve yönetim görevlileri için görüntülenir.
Aşağıdaki görüntüde oturum açmış ve yönetici rolündedir:
Oturum açtığını gösteren ekran görüntüsü
Yöneticinin tüm ayrıcalıkları vardır. Herhangi bir kişiyi okuyabilir, düzenleyebilir veya silebilir ve kişilerin durumunu değiştirebilir.
Uygulama, aşağıdaki modelin iskelesi oluşturularak oluşturulmuştur:
public class Contact
{
public int ContactId { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zip { get; set; }
[DataType(DataType.EmailAddress)]
public string Email { get; set; }
}
Örnek aşağıdaki yetkilendirme işleyicilerini içerir:
- : Kullanıcının yalnızca verilerini düzenleyebilmesini sağlar.
- : Yöneticilerin kişileri onaylamasına veya reddetmesine izin verir.
- : Yöneticilerin kişileri onaylamasına veya reddetmesine ve kişileri düzenlemesine/silmesine izin verir.
Prerequisites
Bu öğretici ileri düzeydir. Aşağıdakiler hakkında bilgi sahibi olmanız gerekir:
- ASP.NET Core
- Authentication
- Hesap Onaylama ve Parola Kurtarma
- Authorization
- Entity Framework Core
Başlangıç ve tamamlanmış uygulama
Tamamlanmış uygulamayı indir. Tamamlanmış uygulamayı test edin ve böylece güvenlik özelliklerine alışın.
Tip
yalnızca örnek alt klasörü indirmek için kullanın. Örneğin:
git clone --depth 1 --filter=blob:none https://github.com/dotnet/AspNetCore.Docs.git --sparse
cd AspNetCore.Docs
git sparse-checkout init --cone
git sparse-checkout set aspnetcore/security/authorization/secure-data/samples
Başlangıç uygulaması
Uygulamayı çalıştırın, ContactManager bağlantısına dokunun ve kişi oluşturabildiğinizi, düzenleyebildiğinizi ve silebildiğinizi doğrulayın. Başlangıç uygulamasını oluşturmak için bkz . Başlangıç uygulamasını oluşturma.
Kullanıcı verilerinin güvenliğini sağlama
Aşağıdaki bölümlerde, güvenli kullanıcı veri uygulamasını oluşturmak için tüm önemli adımlar yer alır. Tamamlanan projeye başvurabilirsiniz, bu yararlı olabilir.
İletişim verilerini kullanıcıya bağlayın
ASP.NET Identity kullanıcı kimliğini kullanarak, kullanıcıların kendi verilerini düzenleyebilmesini, ancak diğer kullanıcıların verilerini düzenleyememesini sağlayın. Modele ve ekleyin:
public class Contact
{
public int ContactId { get; set; }
// user ID from AspNetUser table.
public string? OwnerID { get; set; }
public string? Name { get; set; }
public string? Address { get; set; }
public string? City { get; set; }
public string? State { get; set; }
public string? Zip { get; set; }
[DataType(DataType.EmailAddress)]
public string? Email { get; set; }
public ContactStatus Status { get; set; }
}
public enum ContactStatus
{
Submitted,
Approved,
Rejected
}
, veritabanındaki tablodan kullanıcının kimliğidir. Alan, bir kişi ile ilgili bilginin genel kullanıcılar tarafından görüntülenip görüntülenemeyeceğini belirler.
Yeni bir geçiş oluşturun ve veritabanını güncelleştirin:
dotnet ef migrations add userID_Status
dotnet ef database update
Rol Hizmetlerini Ekleyin
Rol hizmetlerini eklemek için 'Ek' komutunu kullanın:
var builder = WebApplication.CreateBuilder(args);
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<IdentityUser>(
options => options.SignIn.RequireConfirmedAccount = true)
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
Kimliği doğrulanmış kullanıcılar gerektir
Geri dönüş yetkilendirme ilkesini kullanıcıların kimliğinin doğrulanması için ayarlayın:
var builder = WebApplication.CreateBuilder(args);
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<IdentityUser>(
options => options.SignIn.RequireConfirmedAccount = true)
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();
builder.Services.AddAuthorization(options =>
{
options.FallbackPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
});
Önceki vurgulanan kod geri dönüş yetkilendirme ilkesini ayarlar. Yedek yetkilendirme ilkesi, yetkilendirme özelliğine sahip Sayfalar, denetleyiciler veya eylem yöntemleri dışında tüm kullanıcıların kimliklerinin doğrulanmasını gerektirir. Örneğin, sayfalar, denetleyiciler veya eylem yöntemleri, yedek yetkilendirme ilkesi yerine uygulanan yetkilendirme özniteliğini kullanır.
Geçerli kullanıcı kimliğinin doğrulandığından emin olmak için geçerli örneğe ekler.
Geri dönüş yetkilendirme ilkesi:
- Açıkça yetkilendirme ilkesi belirtmeyen tüm isteklere uygulanır. Uç nokta yönlendirme tarafından sunulan istekler için bu, yetkilendirme özniteliği belirtmeyen uç noktaları içerir. Statik dosyalar gibi yetkilendirme ara yazılımından sonra diğer ara yazılım tarafından sunulan istekler için bu, ilkeyi tüm isteklere uygular.
Geri dönüş yetkilendirme ilkesini kullanıcıların kimliğinin doğrulanması için ayarlamak, yeni eklenen Sayfaları ve denetleyicileri korur. Varsayılan olarak gerekli yetkilendirmeye sahip olmak, özniteliğini eklemek için yeni denetleyicilere ve Sayfalara güvenmekten daha güvenlidir.
Sınıf ayrıca şunları içerir: [specific item]. , hiçbir ilke belirtilmediğinde özniteliğiyle birlikte kullanılan ilkedir. , aksine adlandırılmış bir ilke içermez.
İlkeler hakkında daha fazla bilgi için bkz. ASP.NET Core'da Politika tabanlı yetkilendirme.
MVC denetleyicilerinin ve Sayfaların tüm kullanıcıların kimliğini doğrulamasını gerektirmenin alternatif bir yolu yetkilendirme filtresi eklemektir:
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using ContactManager.Data;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.Authorization;
var builder = WebApplication.CreateBuilder(args);
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<IdentityUser>(
options => options.SignIn.RequireConfirmedAccount = true)
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();
builder.Services.AddControllers(config =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
config.Filters.Add(new AuthorizeFilter(policy));
});
var app = builder.Build();
Önceki kodda bir yetkilendirme filtresi kullanılır ve geri dönüş ilkesi ayarlanırken uç nokta yönlendirme kullanılır. Geri dönüş ilkesini ayarlamak, tüm kullanıcıların kimliğinin doğrulanması için tercih edilen yöntemdir.
Anonim kullanıcıların kaydolmadan önce site hakkında bilgi alabilmesi için X ve Y sayfalarına "AllowAnonymous" ekleyin.
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace ContactManager.Pages;
[AllowAnonymous]
public class IndexModel : PageModel
{
private readonly ILogger<IndexModel> _logger;
public IndexModel(ILogger<IndexModel> logger)
{
_logger = logger;
}
public void OnGet()
{
}
}
Test hesabını yapılandırma
Sınıf iki hesap oluşturur: yönetici ve müdür. Bu hesaplar için parola ayarlamak üzere Gizli Yönetici aracını kullanın. parolayı project dizininden (Program.cs içeren dizin) ayarlayın:
dotnet user-secrets set SeedUserPW <PW>
Zayıf bir parola belirtilirse, çağrıldığında bir özel durum oluşturulur.
Uygulamayı test parolasını kullanacak şekilde güncelleştirin:
var builder = WebApplication.CreateBuilder(args);
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<IdentityUser>(
options => options.SignIn.RequireConfirmedAccount = true)
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();
builder.Services.AddAuthorization(options =>
{
options.FallbackPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
});
// Authorization handlers.
builder.Services.AddScoped<IAuthorizationHandler,
ContactIsOwnerAuthorizationHandler>();
builder.Services.AddSingleton<IAuthorizationHandler,
ContactAdministratorsAuthorizationHandler>();
builder.Services.AddSingleton<IAuthorizationHandler,
ContactManagerAuthorizationHandler>();
var app = builder.Build();
using (var scope = app.Services.CreateScope())
{
var services = scope.ServiceProvider;
var context = services.GetRequiredService<ApplicationDbContext>();
context.Database.Migrate();
// requires using Microsoft.Extensions.Configuration;
// Set password with the Secret Manager tool.
// dotnet user-secrets set SeedUserPW <pw>
var testUserPw = builder.Configuration.GetValue<string>("SeedUserPW");
await SeedData.Initialize(services, testUserPw);
}
Test hesaplarını oluşturma ve kişileri güncelleştirme
Test hesaplarını oluşturmak için sınıftaki yöntemi güncelleyin:
public static async Task Initialize(IServiceProvider serviceProvider, string testUserPw)
{
using (var context = new ApplicationDbContext(
serviceProvider.GetRequiredService<DbContextOptions<ApplicationDbContext>>()))
{
// For sample purposes seed both with the same password.
// Password is set with the following:
// dotnet user-secrets set SeedUserPW <pw>
// The admin user can do anything
var adminID = await EnsureUser(serviceProvider, testUserPw, "admin@contoso.com");
await EnsureRole(serviceProvider, adminID, Constants.ContactAdministratorsRole);
// allowed user can create and edit contacts that they create
var managerID = await EnsureUser(serviceProvider, testUserPw, "manager@contoso.com");
await EnsureRole(serviceProvider, managerID, Constants.ContactManagersRole);
SeedDB(context, adminID);
}
}
private static async Task<string> EnsureUser(IServiceProvider serviceProvider,
string testUserPw, string UserName)
{
var userManager = serviceProvider.GetService<UserManager<IdentityUser>>();
var user = await userManager.FindByNameAsync(UserName);
if (user == null)
{
user = new IdentityUser
{
UserName = UserName,
EmailConfirmed = true
};
await userManager.CreateAsync(user, testUserPw);
}
if (user == null)
{
throw new Exception("The password is probably not strong enough!");
}
return user.Id;
}
private static async Task<IdentityResult> EnsureRole(IServiceProvider serviceProvider,
string uid, string role)
{
var roleManager = serviceProvider.GetService<RoleManager<IdentityRole>>();
if (roleManager == null)
{
throw new Exception("roleManager null");
}
IdentityResult IR;
if (!await roleManager.RoleExistsAsync(role))
{
IR = await roleManager.CreateAsync(new IdentityRole(role));
}
var userManager = serviceProvider.GetService<UserManager<IdentityUser>>();
//if (userManager == null)
//{
// throw new Exception("userManager is null");
//}
var user = await userManager.FindByIdAsync(uid);
if (user == null)
{
throw new Exception("The testUserPw password was probably not strong enough!");
}
IR = await userManager.AddToRoleAsync(user, role);
return IR;
}
Yönetici kullanıcı kimliğini kişilere ekleyin. Kişilerden birini "Gönderildi" ve birini "Reddedildi" olarak belirleyin. Tüm kişilere kullanıcı kimliğini ve durumunu ekleyin. Yalnızca bir iletişim görünüyor.
public static void SeedDB(ApplicationDbContext context, string adminID)
{
if (context.Contact.Any())
{
return; // DB has been seeded
}
context.Contact.AddRange(
new Contact
{
Name = "Debra Garcia",
Address = "1234 Main St",
City = "Redmond",
State = "WA",
Zip = "10999",
Email = "debra@example.com",
Status = ContactStatus.Approved,
OwnerID = adminID
},
Sahip, müdür ve yönetici yetkilendirme işleyicileri oluşturma
Yetkilendirme klasöründe bir sınıf oluşturun. bir kaynak üzerinde hareket eden kullanıcının kaynağa sahip olduğunu doğrular.
using ContactManager.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authorization.Infrastructure;
using Microsoft.AspNetCore.Identity;
using System.Threading.Tasks;
namespace ContactManager.Authorization
{
public class ContactIsOwnerAuthorizationHandler
: AuthorizationHandler<OperationAuthorizationRequirement, Contact>
{
UserManager<IdentityUser> _userManager;
public ContactIsOwnerAuthorizationHandler(UserManager<IdentityUser>
userManager)
{
_userManager = userManager;
}
protected override Task
HandleRequirementAsync(AuthorizationHandlerContext context,
OperationAuthorizationRequirement requirement,
Contact resource)
{
if (context.User == null || resource == null)
{
return Task.CompletedTask;
}
// If not asking for CRUD permission, return.
if (requirement.Name != Constants.CreateOperationName &&
requirement.Name != Constants.ReadOperationName &&
requirement.Name != Constants.UpdateOperationName &&
requirement.Name != Constants.DeleteOperationName )
{
return Task.CompletedTask;
}
if (resource.OwnerID == _userManager.GetUserId(context.User))
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
}
Geçerli kimliği doğrulanmış kullanıcı kişi sahibi ise context.Succeed çağrısı yapılır. Yetkilendirme işleyicileri genel olarak:
- Gereksinimler karşılandığında arayın .
- Gereksinimler karşılanmadığında geri dönün . veya 'a önceki bir çağrı olmadan geri dönmek başarılı veya başarısız değildir, diğer yetkilendirme işleyicilerinin çalışmasına izin verir.
Açıkça başarısız olmanız gerekiyorsa, context.Fail'i çağırın.
Uygulama, kişi sahiplerinin kendi verilerini düzenlemesine/silmesine/oluşturmasına olanak tanır. gereksinim parametresinde geçirilen işlemi denetlemesi gerekmez.
Yönetici yetkilendirme işleyicisi oluşturma
Yetkilendirme klasöründe bir sınıf oluşturun. , kaynak üzerinde hareket eden kullanıcının bir yönetici olduğunu doğrular. yalnızca yöneticiler içerik değişikliklerini onaylayabilir veya reddedebilir (yeni veya değiştirilmiş).
using System.Threading.Tasks;
using ContactManager.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authorization.Infrastructure;
using Microsoft.AspNetCore.Identity;
namespace ContactManager.Authorization
{
public class ContactManagerAuthorizationHandler :
AuthorizationHandler<OperationAuthorizationRequirement, Contact>
{
protected override Task
HandleRequirementAsync(AuthorizationHandlerContext context,
OperationAuthorizationRequirement requirement,
Contact resource)
{
if (context.User == null || resource == null)
{
return Task.CompletedTask;
}
// If not asking for approval/reject, return.
if (requirement.Name != Constants.ApproveOperationName &&
requirement.Name != Constants.RejectOperationName)
{
return Task.CompletedTask;
}
// Managers can approve or reject.
if (context.User.IsInRole(Constants.ContactManagersRole))
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
}
Yönetici yetkilendirme işleyicisi oluşturma
Yetkilendirme klasöründe bir sınıf oluşturun. , kaynak üzerinde eylemde bulunan kullanıcının bir yönetici olduğunu doğrular. Yönetici tüm işlemleri yapabilir.
using System.Threading.Tasks;
using ContactManager.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authorization.Infrastructure;
namespace ContactManager.Authorization
{
public class ContactAdministratorsAuthorizationHandler
: AuthorizationHandler<OperationAuthorizationRequirement, Contact>
{
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context,
OperationAuthorizationRequirement requirement,
Contact resource)
{
if (context.User == null)
{
return Task.CompletedTask;
}
// Administrators can do anything.
if (context.User.IsInRole(Constants.ContactAdministratorsRole))
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
}
Yetkilendirme işleyicilerini kaydetme
Entity Framework Core kullanan hizmetlerin bağımlılık enjeksiyonu için kaydedilmesi gerekir.
ContactIsOwnerAuthorizationHandler, Entity Framework Core üzerinde oluşturulan ASP.NET Core Identity kullanır. Hizmet koleksiyonuna kaydedilmeleri için işleyicileri bağımlılık enjeksiyonu ile kullanılabilir hale getirin. aşağıdaki kodu sonuna ekleyin:
var builder = WebApplication.CreateBuilder(args);
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<IdentityUser>(
options => options.SignIn.RequireConfirmedAccount = true)
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();
builder.Services.AddAuthorization(options =>
{
options.FallbackPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
});
// Authorization handlers.
builder.Services.AddScoped<IAuthorizationHandler,
ContactIsOwnerAuthorizationHandler>();
builder.Services.AddSingleton<IAuthorizationHandler,
ContactAdministratorsAuthorizationHandler>();
builder.Services.AddSingleton<IAuthorizationHandler,
ContactManagerAuthorizationHandler>();
var app = builder.Build();
using (var scope = app.Services.CreateScope())
{
var services = scope.ServiceProvider;
var context = services.GetRequiredService<ApplicationDbContext>();
context.Database.Migrate();
// requires using Microsoft.Extensions.Configuration;
// Set password with the Secret Manager tool.
// dotnet user-secrets set SeedUserPW <pw>
var testUserPw = builder.Configuration.GetValue<string>("SeedUserPW");
await SeedData.Initialize(services, testUserPw);
}
ve tekil olarak eklenir. Tekildirler çünkü EF kullanmazlar ve gereken tüm bilgiler yönteminin parametresindedir .
Destek yetkilendirmesi
Bu bölümde Sayfalar'ı güncelleştirir ve bir işlem gereksinimleri sınıfı eklersiniz.
İletişim işlemleri gereksinimleri sınıfını gözden geçirin
Sınıfı gözden geçirin. Bu sınıf, uygulamanın desteklediği gereksinimleri içerir:
using Microsoft.AspNetCore.Authorization.Infrastructure;
namespace ContactManager.Authorization
{
public static class ContactOperations
{
public static OperationAuthorizationRequirement Create =
new OperationAuthorizationRequirement {Name=Constants.CreateOperationName};
public static OperationAuthorizationRequirement Read =
new OperationAuthorizationRequirement {Name=Constants.ReadOperationName};
public static OperationAuthorizationRequirement Update =
new OperationAuthorizationRequirement {Name=Constants.UpdateOperationName};
public static OperationAuthorizationRequirement Delete =
new OperationAuthorizationRequirement {Name=Constants.DeleteOperationName};
public static OperationAuthorizationRequirement Approve =
new OperationAuthorizationRequirement {Name=Constants.ApproveOperationName};
public static OperationAuthorizationRequirement Reject =
new OperationAuthorizationRequirement {Name=Constants.RejectOperationName};
}
public class Constants
{
public static readonly string CreateOperationName = "Create";
public static readonly string ReadOperationName = "Read";
public static readonly string UpdateOperationName = "Update";
public static readonly string DeleteOperationName = "Delete";
public static readonly string ApproveOperationName = "Approve";
public static readonly string RejectOperationName = "Reject";
public static readonly string ContactAdministratorsRole =
"ContactAdministrators";
public static readonly string ContactManagersRole = "ContactManagers";
}
}
Kişi Sayfaları için temel sınıf oluşturma
Kişi Sayfalarında kullanılan hizmetleri içeren bir temel sınıf oluşturun. Temel sınıf başlatma kodunu tek bir konuma yerleştirir:
using ContactManager.Data;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace ContactManager.Pages.Contacts
{
public class DI_BasePageModel : PageModel
{
protected ApplicationDbContext Context { get; }
protected IAuthorizationService AuthorizationService { get; }
protected UserManager<IdentityUser> UserManager { get; }
public DI_BasePageModel(
ApplicationDbContext context,
IAuthorizationService authorizationService,
UserManager<IdentityUser> userManager) : base()
{
Context = context;
UserManager = userManager;
AuthorizationService = authorizationService;
}
}
}
Yukarıdaki kod:
-
IAuthorizationServicehizmetini yetkilendirme işleyicilerine erişim sağlamak için ekler. - Bu hizmeti ekler.
- öğesini ekleyin.
CreateModel'i güncelleştirme
Sayfa oluşturma modelini güncelleştirin:
- Temel sınıfını kullanmak için oluşturucu.
- yöntemi:
- Modele kullanıcı kimliğini ekleyin.
- Kullanıcının kişi oluşturma izni olduğunu doğrulamak için yetkilendirme işleyicisini çağırın.
using ContactManager.Authorization;
using ContactManager.Data;
using ContactManager.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
namespace ContactManager.Pages.Contacts
{
public class CreateModel : DI_BasePageModel
{
public CreateModel(
ApplicationDbContext context,
IAuthorizationService authorizationService,
UserManager<IdentityUser> userManager)
: base(context, authorizationService, userManager)
{
}
public IActionResult OnGet()
{
return Page();
}
[BindProperty]
public Contact Contact { get; set; }
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
Contact.OwnerID = UserManager.GetUserId(User);
var isAuthorized = await AuthorizationService.AuthorizeAsync(
User, Contact,
ContactOperations.Create);
if (!isAuthorized.Succeeded)
{
return Forbid();
}
Context.Contact.Add(Contact);
await Context.SaveChangesAsync();
return RedirectToPage("./Index");
}
}
}
IndexModel'i güncelleştirme
Yöntemi güncelleştirerek yalnızca onaylanan kişilerin genel kullanıcılara gösterilmesini sağlar:
public class IndexModel : DI_BasePageModel
{
public IndexModel(
ApplicationDbContext context,
IAuthorizationService authorizationService,
UserManager<IdentityUser> userManager)
: base(context, authorizationService, userManager)
{
}
public IList<Contact> Contact { get; set; }
public async Task OnGetAsync()
{
var contacts = from c in Context.Contact
select c;
var isAuthorized = User.IsInRole(Constants.ContactManagersRole) ||
User.IsInRole(Constants.ContactAdministratorsRole);
var currentUserId = UserManager.GetUserId(User);
// Only approved contacts are shown UNLESS you're authorized to see them
// or you are the owner.
if (!isAuthorized)
{
contacts = contacts.Where(c => c.Status == ContactStatus.Approved
|| c.OwnerID == currentUserId);
}
Contact = await contacts.ToListAsync();
}
}
EditModel'i güncelleştirme
Kullanıcının iletişim bilgisinin kendisine ait olduğunu doğrulamak için bir yetkilendirme işleyicisi ekleyin. Kaynak yetkilendirmesi doğrulandığından öznitelik yeterli değildir. Öznitelikler değerlendirildiğinde uygulamanın kaynağa erişimi yoktur. Kaynak tabanlı yetkilendirme zorunlu olmalıdır. Uygulama kaynağa erişim sağladığında, sayfa modeline yüklenerek veya doğrudan işleyiciye yüklenerek denetimler gerçekleştirilmelidir. Kaynağa kaynak anahtarını geçirerek sık sık erişirsiniz.
public class EditModel : DI_BasePageModel
{
public EditModel(
ApplicationDbContext context,
IAuthorizationService authorizationService,
UserManager<IdentityUser> userManager)
: base(context, authorizationService, userManager)
{
}
[BindProperty]
public Contact Contact { get; set; }
public async Task<IActionResult> OnGetAsync(int id)
{
Contact? contact = await Context.Contact.FirstOrDefaultAsync(
m => m.ContactId == id);
if (contact == null)
{
return NotFound();
}
Contact = contact;
var isAuthorized = await AuthorizationService.AuthorizeAsync(
User, Contact,
ContactOperations.Update);
if (!isAuthorized.Succeeded)
{
return Forbid();
}
return Page();
}
public async Task<IActionResult> OnPostAsync(int id)
{
if (!ModelState.IsValid)
{
return Page();
}
// Fetch Contact from DB to get OwnerID.
var contact = await Context
.Contact.AsNoTracking()
.FirstOrDefaultAsync(m => m.ContactId == id);
if (contact == null)
{
return NotFound();
}
var isAuthorized = await AuthorizationService.AuthorizeAsync(
User, contact,
ContactOperations.Update);
if (!isAuthorized.Succeeded)
{
return Forbid();
}
Contact.OwnerID = contact.OwnerID;
Context.Attach(Contact).State = EntityState.Modified;
if (Contact.Status == ContactStatus.Approved)
{
// If the contact is updated after approval,
// and the user cannot approve,
// set the status back to submitted so the update can be
// checked and approved.
var canApprove = await AuthorizationService.AuthorizeAsync(User,
Contact,
ContactOperations.Approve);
if (!canApprove.Succeeded)
{
Contact.Status = ContactStatus.Submitted;
}
}
await Context.SaveChangesAsync();
return RedirectToPage("./Index");
}
}
DeleteModel'i güncelleştirme
Silme sayfası modelini, kullanıcının kişi üzerinde silme iznine sahip olduğunu doğrulamak için yetkilendirme işleyicisini kullanacak şekilde güncelleyin.
public class DeleteModel : DI_BasePageModel
{
public DeleteModel(
ApplicationDbContext context,
IAuthorizationService authorizationService,
UserManager<IdentityUser> userManager)
: base(context, authorizationService, userManager)
{
}
[BindProperty]
public Contact Contact { get; set; }
public async Task<IActionResult> OnGetAsync(int id)
{
Contact? _contact = await Context.Contact.FirstOrDefaultAsync(
m => m.ContactId == id);
if (_contact == null)
{
return NotFound();
}
Contact = _contact;
var isAuthorized = await AuthorizationService.AuthorizeAsync(
User, Contact,
ContactOperations.Delete);
if (!isAuthorized.Succeeded)
{
return Forbid();
}
return Page();
}
public async Task<IActionResult> OnPostAsync(int id)
{
var contact = await Context
.Contact.AsNoTracking()
.FirstOrDefaultAsync(m => m.ContactId == id);
if (contact == null)
{
return NotFound();
}
var isAuthorized = await AuthorizationService.AuthorizeAsync(
User, contact,
ContactOperations.Delete);
if (!isAuthorized.Succeeded)
{
return Forbid();
}
Context.Contact.Remove(contact);
await Context.SaveChangesAsync();
return RedirectToPage("./Index");
}
}
Yetkilendirme hizmetini görünümlere ekleme
Kullanıcı arabirimi şu anda kullanıcının değiştiremeyebileceği kişilerin düzenleme ve silme bağlantılarını gösterir.
Yetkilendirme hizmetini tüm görünümlerin kullanımına sunulabilmesi için dosyaya ekleyin:
@using Microsoft.AspNetCore.Identity
@using ContactManager
@using ContactManager.Data
@namespace ContactManager.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@using ContactManager.Authorization;
@using Microsoft.AspNetCore.Authorization
@using ContactManager.Models
@inject IAuthorizationService AuthorizationService
Yukarıdaki işaretleme birkaç deyim ekler.
İçindeki Düzenle ve Sil bağlantılarını yalnızca uygun izinlere sahip kullanıcılar için görünür hale getirin.
@page
@model ContactManager.Pages.Contacts.IndexModel
@{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
<p>
<a asp-page="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Contact[0].Name)
</th>
<th>
@Html.DisplayNameFor(model => model.Contact[0].Address)
</th>
<th>
@Html.DisplayNameFor(model => model.Contact[0].City)
</th>
<th>
@Html.DisplayNameFor(model => model.Contact[0].State)
</th>
<th>
@Html.DisplayNameFor(model => model.Contact[0].Zip)
</th>
<th>
@Html.DisplayNameFor(model => model.Contact[0].Email)
</th>
<th>
@Html.DisplayNameFor(model => model.Contact[0].Status)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.Contact) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.Address)
</td>
<td>
@Html.DisplayFor(modelItem => item.City)
</td>
<td>
@Html.DisplayFor(modelItem => item.State)
</td>
<td>
@Html.DisplayFor(modelItem => item.Zip)
</td>
<td>
@Html.DisplayFor(modelItem => item.Email)
</td>
<td>
@Html.DisplayFor(modelItem => item.Status)
</td>
<td>
@if ((await AuthorizationService.AuthorizeAsync(
User, item,
ContactOperations.Update)).Succeeded)
{
<a asp-page="./Edit" asp-route-id="@item.ContactId">Edit</a>
<text> | </text>
}
<a asp-page="./Details" asp-route-id="@item.ContactId">Details</a>
@if ((await AuthorizationService.AuthorizeAsync(
User, item,
ContactOperations.Delete)).Succeeded)
{
<text> | </text>
<a asp-page="./Delete" asp-route-id="@item.ContactId">Delete</a>
}
</td>
</tr>
}
</tbody>
</table>
Warning
Verileri değiştirme izni olmayan kullanıcıların bağlantılarını gizlemek uygulamanın güvenliğini sağlamaz. Bağlantıları gizlemek, yalnızca geçerli bağlantıları görüntüleyerek uygulamanın daha kullanıcı dostu olmasını sağlar. Kullanıcılar, sahip olmadığı verilerde düzenleme ve silme işlemlerini çağırmak için oluşturulan URL'leri hackleyebilir. Razor Sayfası veya denetleyicisi, verilerin güvenliğini sağlamak için erişim denetimlerini zorunlu kılmalıdır.
Güncelleştirme Ayrıntıları
Yöneticilerin kişileri onaylaması veya reddetmesi için ayrıntılar görünümünü güncelleştirin:
@*Preceding markup omitted for brevity.*@
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Contact.Email)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Contact.Email)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Contact.Status)
</dt>
<dd>
@Html.DisplayFor(model => model.Contact.Status)
</dd>
</dl>
</div>
@if (Model.Contact.Status != ContactStatus.Approved)
{
@if ((await AuthorizationService.AuthorizeAsync(
User, Model.Contact, ContactOperations.Approve)).Succeeded)
{
<form style="display:inline;" method="post">
<input type="hidden" name="id" value="@Model.Contact.ContactId" />
<input type="hidden" name="status" value="@ContactStatus.Approved" />
<button type="submit" class="btn btn-xs btn-success">Approve</button>
</form>
}
}
@if (Model.Contact.Status != ContactStatus.Rejected)
{
@if ((await AuthorizationService.AuthorizeAsync(
User, Model.Contact, ContactOperations.Reject)).Succeeded)
{
<form style="display:inline;" method="post">
<input type="hidden" name="id" value="@Model.Contact.ContactId" />
<input type="hidden" name="status" value="@ContactStatus.Rejected" />
<button type="submit" class="btn btn-xs btn-danger">Reject</button>
</form>
}
}
<div>
@if ((await AuthorizationService.AuthorizeAsync(
User, Model.Contact,
ContactOperations.Update)).Succeeded)
{
<a asp-page="./Edit" asp-route-id="@Model.Contact.ContactId">Edit</a>
<text> | </text>
}
<a asp-page="./Index">Back to List</a>
</div>
Ayrıntılar sayfası modelini güncelleştirme
public class DetailsModel : DI_BasePageModel
{
public DetailsModel(
ApplicationDbContext context,
IAuthorizationService authorizationService,
UserManager<IdentityUser> userManager)
: base(context, authorizationService, userManager)
{
}
public Contact Contact { get; set; }
public async Task<IActionResult> OnGetAsync(int id)
{
Contact? _contact = await Context.Contact.FirstOrDefaultAsync(m => m.ContactId == id);
if (_contact == null)
{
return NotFound();
}
Contact = _contact;
var isAuthorized = User.IsInRole(Constants.ContactManagersRole) ||
User.IsInRole(Constants.ContactAdministratorsRole);
var currentUserId = UserManager.GetUserId(User);
if (!isAuthorized
&& currentUserId != Contact.OwnerID
&& Contact.Status != ContactStatus.Approved)
{
return Forbid();
}
return Page();
}
public async Task<IActionResult> OnPostAsync(int id, ContactStatus status)
{
var contact = await Context.Contact.FirstOrDefaultAsync(
m => m.ContactId == id);
if (contact == null)
{
return NotFound();
}
var contactOperation = (status == ContactStatus.Approved)
? ContactOperations.Approve
: ContactOperations.Reject;
var isAuthorized = await AuthorizationService.AuthorizeAsync(User, contact,
contactOperation);
if (!isAuthorized.Succeeded)
{
return Forbid();
}
contact.Status = status;
Context.Contact.Update(contact);
await Context.SaveChangesAsync();
return RedirectToPage("./Index");
}
}
Bir role kullanıcı ekleme veya bir rolden kullanıcı çıkarma
Aşağıdaki konular hakkında bilgi için bkz. bu konu:
- Bir kullanıcıdan ayrıcalıkları kaldırma. Örneğin, sohbet uygulamasında kullanıcının sesini kapatma.
- Kullanıcıya ayrıcalık ekleme.
Sınama ve Yasak arasındaki farklar
Bu uygulama, varsayılan ilkeyi kimliği doğrulanmış kullanıcılar gerektirecek şekilde ayarlar. Aşağıdaki kod anonim kullanıcılara izin verir. Anonim kullanıcıların Sınama ve Yasak arasındaki farkları göstermesine izin verilir.
[AllowAnonymous]
public class Details2Model : DI_BasePageModel
{
public Details2Model(
ApplicationDbContext context,
IAuthorizationService authorizationService,
UserManager<IdentityUser> userManager)
: base(context, authorizationService, userManager)
{
}
public Contact Contact { get; set; }
public async Task<IActionResult> OnGetAsync(int id)
{
Contact? _contact = await Context.Contact.FirstOrDefaultAsync(m => m.ContactId == id);
if (_contact == null)
{
return NotFound();
}
Contact = _contact;
if (!User.Identity!.IsAuthenticated)
{
return Challenge();
}
var isAuthorized = User.IsInRole(Constants.ContactManagersRole) ||
User.IsInRole(Constants.ContactAdministratorsRole);
var currentUserId = UserManager.GetUserId(User);
if (!isAuthorized
&& currentUserId != Contact.OwnerID
&& Contact.Status != ContactStatus.Approved)
{
return Forbid();
}
return Page();
}
}
Önceki kodda:
- Kullanıcının kimliği doğrulanmadığında bir hata mesajı döndürülür. döndürülürse, kullanıcı oturum açma sayfasına yönlendirilir.
- Kullanıcının kimliği doğrulandığında ancak yetkilendirilmediğinde bir yanıt döndürülür. Bir
ForbidResultdöndürülürse, kullanıcı erişim reddedildi sayfasına yönlendirilir.
Tamamlanan uygulamayı test edin
Warning
Bu makalede, önceden tanımlanmış kullanıcı hesaplarının parolasını depolamak için Secret Manager aracı kullanılır. Sır Yöneticisi aracı, yerel geliştirme sırasında hassas verileri depolamak için kullanılır. Bir uygulama bir test veya üretim ortamına dağıtıldığında kullanılabilecek kimlik doğrulama yordamları hakkında bilgi için bkz. Güvenli kimlik doğrulama akışları.
Yerleşik kullanıcı hesapları için henüz bir parola ayarlamadıysanız, Gizli Yönetici aracını kullanarak bir parola ayarlayın:
Güçlü bir parola seçin:
- En az 12 karakter uzunluğunda ama 14 veya daha fazla karakter daha iyidir.
- Büyük harf, küçük harf, sayı ve simge birleşimi.
- Sözlükte veya bir kişinin, karakterin, ürünün veya kuruluşun adında bulunabilecek bir sözcük değil.
- Önceki parolalarınızdan önemli ölçüde farklıdır.
- Hatırlaman kolay ama başkaları için tahmin etmek zor. "6MonkeysRLooking^" gibi akılda kalıcı bir tümcecik kullanmayı düşünün.
project klasöründen aşağıdaki komutu yürütür; burada
<PW>paroladır:dotnet user-secrets set SeedUserPW <PW>
Uygulamanın kişileri varsa:
- Tablodaki tüm kayıtları silin.
- Veritabanının tohumunu oluşturmak için uygulamayı yeniden başlatın.
Tamamlanmış uygulamayı test etmenin kolay bir yolu, üç farklı tarayıcı (veya gizli/InPrivate oturumları) başlatmaktır. Bir tarayıcıda yeni bir kullanıcı kaydedin (örneğin, ). Her tarayıcıda farklı bir kullanıcıyla oturum açın. Aşağıdaki işlemleri doğrulayın:
- Kayıtlı kullanıcılar, onaylanan tüm iletişim verilerini görüntüleyebilir.
- Kayıtlı kullanıcılar kendi verilerini düzenleyebilir/silebilir.
- Yöneticiler iletişim verilerini onaylayabilir/reddedebilir. Görünümde Onayla ve Reddet düğmeleri gösterilir.
- Yöneticiler tüm verileri onaylayabilir/reddedebilir ve düzenleyebilir/silebilir.
| User | Kişileri onaylama veya reddetme | Options |
|---|---|---|
| test@example.com | No | Verilerini düzenleyin ve silin. |
| manager@contoso.com | Yes | Verilerini düzenleyin ve silin. |
| admin@contoso.com | Yes | Tüm verileri düzenleyin ve silin. |
Yöneticinin tarayıcısında bir iletişim oluşturun. Yönetici iletişim bilgisinden silme ve değiştirme URL'sini kopyalayın. Test kullanıcısının bu işlemleri gerçekleştiremadığını doğrulamak için bu bağlantıları test kullanıcısının tarayıcısına yapıştırın.
Başlangıç uygulamasını oluşturma
"ContactManager" adlı bir Pages uygulaması oluşturma
- Bireysel Hesaplar ile uygulamayı oluşturun.
- Ad alanının örnekte kullanılan ad alanıyla eşleşmesi için "ContactManager" olarak adlandırın.
- SQLite yerine LocalDB belirtir
dotnet new webapp -o ContactManager -au Individual -uldEkleme : secure-data\samples\starter6\ContactManager\Models\Contact.cs
using System.ComponentModel.DataAnnotations; namespace ContactManager.Models { public class Contact { public int ContactId { get; set; } public string? Name { get; set; } public string? Address { get; set; } public string? City { get; set; } public string? State { get; set; } public string? Zip { get; set; } [DataType(DataType.EmailAddress)] public string? Email { get; set; } } }Modelin iskelesini oluşturma .
İlk geçişi oluşturun ve veritabanını güncelleştirin:
dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design
dotnet tool install -g dotnet-aspnet-codegenerator
dotnet-aspnet-codegenerator razorpage -m Contact -udl -dc ApplicationDbContext -outDir Pages\Contacts --referenceScriptLibraries
dotnet ef database drop -f
dotnet ef migrations add initial
dotnet ef database update
Note
Varsayılan olarak yüklenecek .NET ikili dosyalarının mimarisi şu anda çalışan işletim sistemi mimarisini temsil eder. Farklı bir işletim sistemi mimarisi belirtmek için bkz . dotnet tool install, --arch option. Daha fazla bilgi için bkz. GitHub sorun dotnet/AspNetCore.Docs #29262.
Dosyadaki ContactManager tutturucuyu güncelleştirin :
<a class="nav-link text-dark" asp-area="" asp-page="/Contacts/Index">Contact Manager</a>Kişi oluşturarak, düzenleyerek ve silerek uygulamayı test edin
Veritabanının tohumunu oluşturma
SeedData sınıfını Data klasörüne ekleyin:
using ContactManager.Models;
using Microsoft.EntityFrameworkCore;
// dotnet aspnet-codegenerator razorpage -m Contact -dc ApplicationDbContext -udl -outDir Pages\Contacts --referenceScriptLibraries
namespace ContactManager.Data
{
public static class SeedData
{
public static async Task Initialize(IServiceProvider serviceProvider, string testUserPw="")
{
using (var context = new ApplicationDbContext(
serviceProvider.GetRequiredService<DbContextOptions<ApplicationDbContext>>()))
{
SeedDB(context, testUserPw);
}
}
public static void SeedDB(ApplicationDbContext context, string adminID)
{
if (context.Contact.Any())
{
return; // DB has been seeded
}
context.Contact.AddRange(
new Contact
{
Name = "Debra Garcia",
Address = "1234 Main St",
City = "Redmond",
State = "WA",
Zip = "10999",
Email = "debra@example.com"
},
new Contact
{
Name = "Thorsten Weinrich",
Address = "5678 1st Ave W",
City = "Redmond",
State = "WA",
Zip = "10999",
Email = "thorsten@example.com"
},
new Contact
{
Name = "Yuhong Li",
Address = "9012 State st",
City = "Redmond",
State = "WA",
Zip = "10999",
Email = "yuhong@example.com"
},
new Contact
{
Name = "Jon Orton",
Address = "3456 Maple St",
City = "Redmond",
State = "WA",
Zip = "10999",
Email = "jon@example.com"
},
new Contact
{
Name = "Diliana Alexieva-Bosseva",
Address = "7890 2nd Ave E",
City = "Redmond",
State = "WA",
Zip = "10999",
Email = "diliana@example.com"
}
);
context.SaveChanges();
}
}
}
Çağrı şuradan:
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using ContactManager.Data;
var builder = WebApplication.CreateBuilder(args);
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();
var app = builder.Build();
using (var scope = app.Services.CreateScope())
{
var services = scope.ServiceProvider;
await SeedData.Initialize(services);
}
if (app.Environment.IsDevelopment())
{
app.UseMigrationsEndPoint();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapRazorPages();
app.Run();
Uygulamanın veritabanını doldurduğunu test edin. İletişim veritabanında herhangi bir satır varsa, seed yöntemi çalışmaz.
Bu öğreticide, yetkilendirmeyle korunan kullanıcı verileriyle bir ASP.NET Core web uygulamasının nasıl oluşturulacağı gösterilmektedir. Kimliği doğrulanmış (kayıtlı) kullanıcıların oluşturduğu kişilerin listesini görüntüler. Üç güvenlik grubu vardır:
- Kayıtlı kullanıcılar onaylanan tüm verileri görüntüleyebilir ve kendi verilerini düzenleyebilir/silebilir.
- Yöneticiler iletişim verilerini onaylayabilir veya reddedebilir. Yalnızca onaylanan kişiler kullanıcılar tarafından görülebilir.
- Yöneticiler tüm verileri onaylayabilir/reddedebilir ve düzenleyebilir/silebilir.
Bu belgedeki resimler en son şablonlarla tam olarak eşleşmiyor.
Aşağıdaki görüntüde Rick () kullanıcısı oturum açmış. Rick yalnızca onaylanan kişileri görüntüleyebilir ve kişileri için Düzenle, Sil, Yeni Oluştur bağlantılarını görebilir. Yalnızca Rick tarafından oluşturulan son kayıt Düzenle ve Sil bağlantılarını görüntüler. Yönetici veya yönetici durumu "Onaylandı" olarak değiştirene kadar diğer kullanıcılar son kaydı görmez.
Rick'in oturum açtığını gösteren ekran görüntüsü
Aşağıdaki görüntüde, yöneticinin rolünde oturum açmıştır:
Oturum açtığını gösteren ekran görüntüsü
Aşağıdaki görüntüde, bir kişinin yönetici ayrıntıları görünümü gösterilmektedir:
Yöneticinin kontak görüşü
Onayla ve Reddet düğmeleri yalnızca yöneticiler ve yönetim görevlileri için görüntülenir.
Aşağıdaki görüntüde oturum açmış ve yönetici rolündedir:
Oturum açtığını gösteren ekran görüntüsü
Yöneticinin tüm ayrıcalıkları vardır. Herhangi bir kişinin bilgilerini okuyabilir, düzenleyebilir veya silebilir ve kişilerin durumunu değiştirebilir.
Uygulama, aşağıdaki modelin iskelesi oluşturularak oluşturulmuştur:
public class Contact
{
public int ContactId { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zip { get; set; }
[DataType(DataType.EmailAddress)]
public string Email { get; set; }
}
Örnek aşağıdaki yetkilendirme işleyicilerini içerir:
- : Kullanıcının yalnızca verilerini düzenleyebilmesini sağlar.
- : Yöneticilerin kişileri onaylamasına veya reddetmesine izin verir.
- : Yöneticilerin şunları yapmasına izin verir:
- Kişileri onaylama veya reddetme
- Kişileri düzenleme ve silme
Prerequisites
Bu öğretici ileri düzeydir. Aşağıdakiler hakkında bilgi sahibi olmanız gerekir:
- ASP.NET Core
- Authentication
- Hesap Onaylama ve Parola Kurtarma
- Authorization
- Entity Framework Core
Başlangıç ve tamamlanmış uygulama
Tamamlanmış uygulamayı indir. Tamamlanmış uygulamayı test edin ve böylece güvenlik özelliklerine alışın.
Başlangıç uygulaması
Uygulamayı çalıştırın, ContactManager bağlantısına dokunun ve kişi oluşturabildiğinizi, düzenleyebildiğinizi ve silebildiğinizi doğrulayın. Başlangıç uygulamasını oluşturmak için bkz . Başlangıç uygulamasını oluşturma.
Kullanıcı verilerinin güvenliğini sağlama
Aşağıdaki bölümlerde, güvenli kullanıcı veri uygulamasını oluşturmak için tüm önemli adımlar yer alır. Tamamlanan projeye başvurabilirsiniz, bu yararlı olabilir.
İletişim verilerini kullanıcıya bağlayın
ASP.NET Identity kullanıcı kimliğini kullanarak, kullanıcıların kendi verilerini düzenleyebilmesini, ancak diğer kullanıcıların verilerini düzenleyememesini sağlayın. Modele [ ] ve [ ] ekleyin:
public class Contact
{
public int ContactId { get; set; }
// user ID from AspNetUser table.
public string OwnerID { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zip { get; set; }
[DataType(DataType.EmailAddress)]
public string Email { get; set; }
public ContactStatus Status { get; set; }
}
public enum ContactStatus
{
Submitted,
Approved,
Rejected
}
, veritabanındaki tablodan kullanıcının kimliğidir. Bir alan, bir kişinin iletişim bilgilerini genel kullanıcıların görüntüleyip görüntüleyemeyeceğini belirler.
Yeni bir geçiş oluşturun ve veritabanını güncelleştirin:
dotnet ef migrations add userID_Status
dotnet ef database update
Rol hizmetlerini ekle
Rol hizmetlerini eklemek için ekleme yapın:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<IdentityUser>(
options => options.SignIn.RequireConfirmedAccount = true)
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
Kimliği doğrulanmış kullanıcılar gerektir
Geri dönüş kimlik doğrulama ilkesini kullanıcıların kimliğinin doğrulanması için ayarlayın:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<IdentityUser>(
options => options.SignIn.RequireConfirmedAccount = true)
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddRazorPages();
services.AddAuthorization(options =>
{
options.FallbackPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
});
Önceki vurgulanan kod, geri dönüş kimlik doğrulama ilkesini ayarlar. Geri dönüş kimlik doğrulama politikası, kimlik doğrulama özniteliği olan sayfalar, denetleyiciler veya eylem yöntemleri haricinde tüm kullanıcıların kimliğinin doğrulanmasını gerektirir. Örneğin, Sayfalar, denetleyiciler veya eylem yöntemleri uygulanan kimlik doğrulama özniteliğini kullanır, geri dönüş kimlik doğrulama politikası yerine.
geçerli kullanıcının kimliğinin doğrulandığını zorlayan geçerli örneğe ekler .
Geri dönüş kimlik doğrulaması ilkesi:
- Açıkça kimlik doğrulama ilkesi belirtmeyen tüm isteklere uygulanır. Uç nokta yönlendirme tarafından sunulan istekler için bu, yetkilendirme özniteliği belirtmeyen uç noktaları içerir. Statik dosyalar gibi yetkilendirme ara yazılımından sonra diğer ara yazılım tarafından sunulan istekler için bu, ilkeyi tüm isteklere uygular.
Geri dönüş kimlik doğrulama ilkesini kullanıcıların kimliğinin doğrulanması gerektirecek şekilde ayarlamak, yeni eklenen Sayfaları ve denetleyicileri korur. Kimlik doğrulamasının varsayılan olarak gerekli olması, özniteliğini eklemek için yeni denetleyicilere ve Sayfalara güvenmekten daha güvenlidir.
sınıfı da içerir . , hiçbir ilke belirtilmediğinde özniteliğiyle birlikte kullanılan ilkedir. , aksine adlandırılmış bir ilke içermez.
İlkeler hakkında daha fazla bilgi için, bkz. ASP.NET Core'da Politikaya dayalı yetkilendirme.
MVC denetleyicilerinin ve Sayfaların tüm kullanıcıların kimliğini doğrulamasını gerektirmenin alternatif bir yolu yetkilendirme filtresi eklemektir:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<IdentityUser>(
options => options.SignIn.RequireConfirmedAccount = true)
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddRazorPages();
services.AddControllers(config =>
{
// using Microsoft.AspNetCore.Mvc.Authorization;
// using Microsoft.AspNetCore.Authorization;
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
config.Filters.Add(new AuthorizeFilter(policy));
});
Önceki kodda bir yetkilendirme filtresi kullanılır ve geri dönüş ilkesi ayarlanırken uç nokta yönlendirme kullanılır. Geri dönüş ilkesini ayarlamak, tüm kullanıcıların kimliğinin doğrulanması için tercih edilen yöntemdir.
Anonim kullanıcıların kaydolmadan önce site hakkında bilgi alabilmesi için
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
namespace ContactManager.Pages
{
[AllowAnonymous]
public class IndexModel : PageModel
{
private readonly ILogger<IndexModel> _logger;
public IndexModel(ILogger<IndexModel> logger)
{
_logger = logger;
}
public void OnGet()
{
}
}
}
Test hesabını yapılandırma
Sınıf iki hesap oluşturur: yönetici ve müdür. Bu hesaplar için parola ayarlamak için Gizli Yönetici aracını kullanın. parolayı project dizininden (Program.cs içeren dizin) ayarlayın:
dotnet user-secrets set SeedUserPW <PW>
Güçlü bir parola belirtilmezse, çağrıldığında bir özel durum fırlatılır.
Test parolasını kullanacak şekilde güncelleştirin :
public class Program
{
public static void Main(string[] args)
{
var host = CreateHostBuilder(args).Build();
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
try
{
var context = services.GetRequiredService<ApplicationDbContext>();
context.Database.Migrate();
// requires using Microsoft.Extensions.Configuration;
var config = host.Services.GetRequiredService<IConfiguration>();
// Set password with the Secret Manager tool.
// dotnet user-secrets set SeedUserPW <pw>
var testUserPw = config["SeedUserPW"];
SeedData.Initialize(services, testUserPw).Wait();
}
catch (Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred seeding the DB.");
}
}
host.Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
Test hesaplarını oluşturma ve kişileri güncelleştirme
Sınıftaki yöntemi, test hesaplarını oluşturmak için güncelleyin.
public static async Task Initialize(IServiceProvider serviceProvider, string testUserPw)
{
using (var context = new ApplicationDbContext(
serviceProvider.GetRequiredService<DbContextOptions<ApplicationDbContext>>()))
{
// For sample purposes seed both with the same password.
// Password is set with the following:
// dotnet user-secrets set SeedUserPW <pw>
// The admin user can do anything
var adminID = await EnsureUser(serviceProvider, testUserPw, "admin@contoso.com");
await EnsureRole(serviceProvider, adminID, Constants.ContactAdministratorsRole);
// allowed user can create and edit contacts that they create
var managerID = await EnsureUser(serviceProvider, testUserPw, "manager@contoso.com");
await EnsureRole(serviceProvider, managerID, Constants.ContactManagersRole);
SeedDB(context, adminID);
}
}
private static async Task<string> EnsureUser(IServiceProvider serviceProvider,
string testUserPw, string UserName)
{
var userManager = serviceProvider.GetService<UserManager<IdentityUser>>();
var user = await userManager.FindByNameAsync(UserName);
if (user == null)
{
user = new IdentityUser
{
UserName = UserName,
EmailConfirmed = true
};
await userManager.CreateAsync(user, testUserPw);
}
if (user == null)
{
throw new Exception("The password is probably not strong enough!");
}
return user.Id;
}
private static async Task<IdentityResult> EnsureRole(IServiceProvider serviceProvider,
string uid, string role)
{
var roleManager = serviceProvider.GetService<RoleManager<IdentityRole>>();
if (roleManager == null)
{
throw new Exception("roleManager null");
}
IdentityResult IR;
if (!await roleManager.RoleExistsAsync(role))
{
IR = await roleManager.CreateAsync(new IdentityRole(role));
}
var userManager = serviceProvider.GetService<UserManager<IdentityUser>>();
//if (userManager == null)
//{
// throw new Exception("userManager is null");
//}
var user = await userManager.FindByIdAsync(uid);
if (user == null)
{
throw new Exception("The testUserPw password was probably not strong enough!");
}
IR = await userManager.AddToRoleAsync(user, role);
return IR;
}
Yönetici kullanıcı kimliğini ve kişilerine ekleyin. İletişimlerden birini "Gönderildi" ve birini "Reddedildi" yapın. Tüm kişilere kullanıcı kimliğini ve durumunu ekleyin. Yalnızca bir iletişim görünüyor.
public static void SeedDB(ApplicationDbContext context, string adminID)
{
if (context.Contact.Any())
{
return; // DB has been seeded
}
context.Contact.AddRange(
new Contact
{
Name = "Debra Garcia",
Address = "1234 Main St",
City = "Redmond",
State = "WA",
Zip = "10999",
Email = "debra@example.com",
Status = ContactStatus.Approved,
OwnerID = adminID
},
Sahip, müdür ve yönetici yetkilendirme işleyicileri oluşturma
Yetkilendirme klasöründe bir sınıf oluşturun. bir kaynak üzerinde hareket eden kullanıcının kaynağa sahip olduğunu doğrular.
using ContactManager.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authorization.Infrastructure;
using Microsoft.AspNetCore.Identity;
using System.Threading.Tasks;
namespace ContactManager.Authorization
{
public class ContactIsOwnerAuthorizationHandler
: AuthorizationHandler<OperationAuthorizationRequirement, Contact>
{
UserManager<IdentityUser> _userManager;
public ContactIsOwnerAuthorizationHandler(UserManager<IdentityUser>
userManager)
{
_userManager = userManager;
}
protected override Task
HandleRequirementAsync(AuthorizationHandlerContext context,
OperationAuthorizationRequirement requirement,
Contact resource)
{
if (context.User == null || resource == null)
{
return Task.CompletedTask;
}
// If not asking for CRUD permission, return.
if (requirement.Name != Constants.CreateOperationName &&
requirement.Name != Constants.ReadOperationName &&
requirement.Name != Constants.UpdateOperationName &&
requirement.Name != Constants.DeleteOperationName )
{
return Task.CompletedTask;
}
if (resource.OwnerID == _userManager.GetUserId(context.User))
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
}
Geçerli kimliği doğrulanmış kullanıcı kişi sahibi ise context.Succeed çağrısı yapılır. Yetkilendirme işleyicileri genel olarak:
- Gereksinimler karşılandığında arayın .
- Gereksinimler karşılanmadığında geri dönün . veya 'a önceki bir çağrı olmadan geri dönmek başarılı veya başarısız değildir, diğer yetkilendirme işleyicilerinin çalışmasına izin verir.
Açıkça başarısız olmanız gerekiyorsa, context.Fail'i çağırın.
Uygulama, kişi sahiplerinin kendi verilerini düzenlemesine/silmesine/oluşturmasına olanak tanır. gereksinim parametresinde geçirilen işlemi denetlemesi gerekmez.
Yönetici yetkilendirme işleyicisi oluşturma
Yetkilendirme klasöründe bir sınıf oluşturun. , kaynak üzerinde hareket eden kullanıcının bir yönetici olduğunu doğrular. yalnızca yöneticiler içerik değişikliklerini onaylayabilir veya reddedebilir (yeni veya değiştirilmiş).
using System.Threading.Tasks;
using ContactManager.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authorization.Infrastructure;
using Microsoft.AspNetCore.Identity;
namespace ContactManager.Authorization
{
public class ContactManagerAuthorizationHandler :
AuthorizationHandler<OperationAuthorizationRequirement, Contact>
{
protected override Task
HandleRequirementAsync(AuthorizationHandlerContext context,
OperationAuthorizationRequirement requirement,
Contact resource)
{
if (context.User == null || resource == null)
{
return Task.CompletedTask;
}
// If not asking for approval/reject, return.
if (requirement.Name != Constants.ApproveOperationName &&
requirement.Name != Constants.RejectOperationName)
{
return Task.CompletedTask;
}
// Managers can approve or reject.
if (context.User.IsInRole(Constants.ContactManagersRole))
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
}
Yönetici yetkilendirme işleyicisi oluşturma
Yetkilendirme klasöründe bir sınıf oluşturun. , kaynak üzerinde eylemde bulunan kullanıcının bir yönetici olduğunu doğrular. Yönetici tüm işlemleri yapabilir.
using System.Threading.Tasks;
using ContactManager.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authorization.Infrastructure;
namespace ContactManager.Authorization
{
public class ContactAdministratorsAuthorizationHandler
: AuthorizationHandler<OperationAuthorizationRequirement, Contact>
{
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context,
OperationAuthorizationRequirement requirement,
Contact resource)
{
if (context.User == null)
{
return Task.CompletedTask;
}
// Administrators can do anything.
if (context.User.IsInRole(Constants.ContactAdministratorsRole))
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
}
Yetkilendirme işleyicilerini kaydetme
Entity Framework Core kullanan hizmetlerin bağımlılık enjeksiyonu için kaydedilmesi gerekir.
ContactIsOwnerAuthorizationHandler, Entity Framework Core üzerinde oluşturulan ASP.NET Core Identity kullanır. Hizmet koleksiyonuna kaydedilmeleri için işleyicileri bağımlılık enjeksiyonu ile kullanılabilir hale getirin. aşağıdaki kodu sonuna ekleyin:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<IdentityUser>(
options => options.SignIn.RequireConfirmedAccount = true)
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddRazorPages();
services.AddAuthorization(options =>
{
options.FallbackPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
});
// Authorization handlers.
services.AddScoped<IAuthorizationHandler,
ContactIsOwnerAuthorizationHandler>();
services.AddSingleton<IAuthorizationHandler,
ContactAdministratorsAuthorizationHandler>();
services.AddSingleton<IAuthorizationHandler,
ContactManagerAuthorizationHandler>();
}
ve tekil olarak eklenir. Tekildirler çünkü EF kullanmazlar ve gereken tüm bilgiler yönteminin parametresindedir .
Destek yetkilendirmesi
Bu bölümde Sayfalar'ı güncelleştirir ve bir işlem gereksinimleri sınıfı eklersiniz.
İletişim işlemleri gereksinimleri sınıfını gözden geçirin
Sınıfı gözden geçirin. Bu sınıf, uygulamanın desteklediği gereksinimleri içerir:
using Microsoft.AspNetCore.Authorization.Infrastructure;
namespace ContactManager.Authorization
{
public static class ContactOperations
{
public static OperationAuthorizationRequirement Create =
new OperationAuthorizationRequirement {Name=Constants.CreateOperationName};
public static OperationAuthorizationRequirement Read =
new OperationAuthorizationRequirement {Name=Constants.ReadOperationName};
public static OperationAuthorizationRequirement Update =
new OperationAuthorizationRequirement {Name=Constants.UpdateOperationName};
public static OperationAuthorizationRequirement Delete =
new OperationAuthorizationRequirement {Name=Constants.DeleteOperationName};
public static OperationAuthorizationRequirement Approve =
new OperationAuthorizationRequirement {Name=Constants.ApproveOperationName};
public static OperationAuthorizationRequirement Reject =
new OperationAuthorizationRequirement {Name=Constants.RejectOperationName};
}
public class Constants
{
public static readonly string CreateOperationName = "Create";
public static readonly string ReadOperationName = "Read";
public static readonly string UpdateOperationName = "Update";
public static readonly string DeleteOperationName = "Delete";
public static readonly string ApproveOperationName = "Approve";
public static readonly string RejectOperationName = "Reject";
public static readonly string ContactAdministratorsRole =
"ContactAdministrators";
public static readonly string ContactManagersRole = "ContactManagers";
}
}
Kişi Sayfaları için temel sınıf oluşturma
Kişi Sayfalarında kullanılan hizmetleri içeren bir temel sınıf oluşturun. Temel sınıf başlatma kodunu tek bir konuma yerleştirir:
using ContactManager.Data;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace ContactManager.Pages.Contacts
{
public class DI_BasePageModel : PageModel
{
protected ApplicationDbContext Context { get; }
protected IAuthorizationService AuthorizationService { get; }
protected UserManager<IdentityUser> UserManager { get; }
public DI_BasePageModel(
ApplicationDbContext context,
IAuthorizationService authorizationService,
UserManager<IdentityUser> userManager) : base()
{
Context = context;
UserManager = userManager;
AuthorizationService = authorizationService;
}
}
}
Yukarıdaki kod:
-
IAuthorizationServicehizmetini yetkilendirme işleyicilerine erişim sağlamak için ekler. - Bu hizmeti ekler.
- öğesini ekleyin.
CreateModel'i güncelleştirme
Oluşturma sayfası modeli oluşturucuyu temel sınıfı kullanacak şekilde güncelleştirin :
public class CreateModel : DI_BasePageModel
{
public CreateModel(
ApplicationDbContext context,
IAuthorizationService authorizationService,
UserManager<IdentityUser> userManager)
: base(context, authorizationService, userManager)
{
}
yöntemini şu şekilde güncelleştirin :
- Modele kullanıcı kimliğini ekleyin.
- Kullanıcının kişi oluşturma izni olduğunu doğrulamak için yetkilendirme işleyicisini çağırın.
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
Contact.OwnerID = UserManager.GetUserId(User);
// requires using ContactManager.Authorization;
var isAuthorized = await AuthorizationService.AuthorizeAsync(
User, Contact,
ContactOperations.Create);
if (!isAuthorized.Succeeded)
{
return Forbid();
}
Context.Contact.Add(Contact);
await Context.SaveChangesAsync();
return RedirectToPage("./Index");
}
IndexModel'i güncelleştirme
Yöntemi güncelleştirerek yalnızca onaylanan kişilerin genel kullanıcılara gösterilmesini sağlar:
public class IndexModel : DI_BasePageModel
{
public IndexModel(
ApplicationDbContext context,
IAuthorizationService authorizationService,
UserManager<IdentityUser> userManager)
: base(context, authorizationService, userManager)
{
}
public IList<Contact> Contact { get; set; }
public async Task OnGetAsync()
{
var contacts = from c in Context.Contact
select c;
var isAuthorized = User.IsInRole(Constants.ContactManagersRole) ||
User.IsInRole(Constants.ContactAdministratorsRole);
var currentUserId = UserManager.GetUserId(User);
// Only approved contacts are shown UNLESS you're authorized to see them
// or you are the owner.
if (!isAuthorized)
{
contacts = contacts.Where(c => c.Status == ContactStatus.Approved
|| c.OwnerID == currentUserId);
}
Contact = await contacts.ToListAsync();
}
}
EditModel'i güncelleştirme
Kullanıcının iletişim bilgisinin kendisine ait olduğunu doğrulamak için bir yetkilendirme işleyicisi ekleyin. Kaynak yetkilendirmesi doğrulandığından öznitelik yeterli değildir. Öznitelikler değerlendirildiğinde uygulamanın kaynağa erişimi yoktur. Kaynak tabanlı yetkilendirme zorunlu olmalıdır. Uygulama kaynağa erişim sağladığında, sayfa modeline yüklenerek veya doğrudan işleyiciye yüklenerek denetimler gerçekleştirilmelidir. Kaynağa kaynak anahtarını geçirerek sık sık erişirsiniz.
public class EditModel : DI_BasePageModel
{
public EditModel(
ApplicationDbContext context,
IAuthorizationService authorizationService,
UserManager<IdentityUser> userManager)
: base(context, authorizationService, userManager)
{
}
[BindProperty]
public Contact Contact { get; set; }
public async Task<IActionResult> OnGetAsync(int id)
{
Contact = await Context.Contact.FirstOrDefaultAsync(
m => m.ContactId == id);
if (Contact == null)
{
return NotFound();
}
var isAuthorized = await AuthorizationService.AuthorizeAsync(
User, Contact,
ContactOperations.Update);
if (!isAuthorized.Succeeded)
{
return Forbid();
}
return Page();
}
public async Task<IActionResult> OnPostAsync(int id)
{
if (!ModelState.IsValid)
{
return Page();
}
// Fetch Contact from DB to get OwnerID.
var contact = await Context
.Contact.AsNoTracking()
.FirstOrDefaultAsync(m => m.ContactId == id);
if (contact == null)
{
return NotFound();
}
var isAuthorized = await AuthorizationService.AuthorizeAsync(
User, contact,
ContactOperations.Update);
if (!isAuthorized.Succeeded)
{
return Forbid();
}
Contact.OwnerID = contact.OwnerID;
Context.Attach(Contact).State = EntityState.Modified;
if (Contact.Status == ContactStatus.Approved)
{
// If the contact is updated after approval,
// and the user cannot approve,
// set the status back to submitted so the update can be
// checked and approved.
var canApprove = await AuthorizationService.AuthorizeAsync(User,
Contact,
ContactOperations.Approve);
if (!canApprove.Succeeded)
{
Contact.Status = ContactStatus.Submitted;
}
}
await Context.SaveChangesAsync();
return RedirectToPage("./Index");
}
}
DeleteModel'i güncelleştirme
Silme sayfası modelini, kullanıcının kişi üzerinde silme iznine sahip olduğunu doğrulamak için yetkilendirme işleyicisini kullanacak şekilde güncelleyin.
public class DeleteModel : DI_BasePageModel
{
public DeleteModel(
ApplicationDbContext context,
IAuthorizationService authorizationService,
UserManager<IdentityUser> userManager)
: base(context, authorizationService, userManager)
{
}
[BindProperty]
public Contact Contact { get; set; }
public async Task<IActionResult> OnGetAsync(int id)
{
Contact = await Context.Contact.FirstOrDefaultAsync(
m => m.ContactId == id);
if (Contact == null)
{
return NotFound();
}
var isAuthorized = await AuthorizationService.AuthorizeAsync(
User, Contact,
ContactOperations.Delete);
if (!isAuthorized.Succeeded)
{
return Forbid();
}
return Page();
}
public async Task<IActionResult> OnPostAsync(int id)
{
var contact = await Context
.Contact.AsNoTracking()
.FirstOrDefaultAsync(m => m.ContactId == id);
if (contact == null)
{
return NotFound();
}
var isAuthorized = await AuthorizationService.AuthorizeAsync(
User, contact,
ContactOperations.Delete);
if (!isAuthorized.Succeeded)
{
return Forbid();
}
Context.Contact.Remove(contact);
await Context.SaveChangesAsync();
return RedirectToPage("./Index");
}
}
Yetkilendirme hizmetini görünümlere ekleme
Kullanıcı arabirimi şu anda kullanıcının değiştiremeyebileceği kişilerin düzenleme ve silme bağlantılarını gösterir.
Yetkilendirme hizmetini tüm görünümlerin kullanımına sunulabilmesi için dosyaya ekleyin:
@using Microsoft.AspNetCore.Identity
@using ContactManager
@using ContactManager.Data
@namespace ContactManager.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@using ContactManager.Authorization;
@using Microsoft.AspNetCore.Authorization
@using ContactManager.Models
@inject IAuthorizationService AuthorizationService
Yukarıdaki işaretleme birkaç deyim ekler.
İçindeki Düzenle ve Sil bağlantılarını yalnızca uygun izinlere sahip kullanıcılar için görünür hale getirin.
@page
@model ContactManager.Pages.Contacts.IndexModel
@{
ViewData["Title"] = "Index";
}
<h2>Index</h2>
<p>
<a asp-page="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Contact[0].Name)
</th>
<th>
@Html.DisplayNameFor(model => model.Contact[0].Address)
</th>
<th>
@Html.DisplayNameFor(model => model.Contact[0].City)
</th>
<th>
@Html.DisplayNameFor(model => model.Contact[0].State)
</th>
<th>
@Html.DisplayNameFor(model => model.Contact[0].Zip)
</th>
<th>
@Html.DisplayNameFor(model => model.Contact[0].Email)
</th>
<th>
@Html.DisplayNameFor(model => model.Contact[0].Status)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.Contact)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.Address)
</td>
<td>
@Html.DisplayFor(modelItem => item.City)
</td>
<td>
@Html.DisplayFor(modelItem => item.State)
</td>
<td>
@Html.DisplayFor(modelItem => item.Zip)
</td>
<td>
@Html.DisplayFor(modelItem => item.Email)
</td>
<td>
@Html.DisplayFor(modelItem => item.Status)
</td>
<td>
@if ((await AuthorizationService.AuthorizeAsync(
User, item,
ContactOperations.Update)).Succeeded)
{
<a asp-page="./Edit" asp-route-id="@item.ContactId">Edit</a>
<text> | </text>
}
<a asp-page="./Details" asp-route-id="@item.ContactId">Details</a>
@if ((await AuthorizationService.AuthorizeAsync(
User, item,
ContactOperations.Delete)).Succeeded)
{
<text> | </text>
<a asp-page="./Delete" asp-route-id="@item.ContactId">Delete</a>
}
</td>
</tr>
}
</tbody>
</table>
Warning
Verileri değiştirme izni olmayan kullanıcıların bağlantılarını gizlemek uygulamanın güvenliğini sağlamaz. Bağlantıları gizlemek, yalnızca geçerli bağlantıları görüntüleyerek uygulamanın daha kullanıcı dostu olmasını sağlar. Kullanıcılar, sahip olmadığı verilerde düzenleme ve silme işlemlerini çağırmak için oluşturulan URL'leri hackleyebilir. Razor Sayfası veya denetleyicisi, verilerin güvenliğini sağlamak için erişim denetimlerini zorunlu kılmalıdır.
Güncelleştirme Ayrıntıları
Yöneticilerin kişileri onaylaması veya reddetmesi için ayrıntılar görünümünü güncelleştirin:
@*Precedng markup omitted for brevity.*@
<dt>
@Html.DisplayNameFor(model => model.Contact.Email)
</dt>
<dd>
@Html.DisplayFor(model => model.Contact.Email)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Contact.Status)
</dt>
<dd>
@Html.DisplayFor(model => model.Contact.Status)
</dd>
</dl>
</div>
@if (Model.Contact.Status != ContactStatus.Approved)
{
@if ((await AuthorizationService.AuthorizeAsync(
User, Model.Contact, ContactOperations.Approve)).Succeeded)
{
<form style="display:inline;" method="post">
<input type="hidden" name="id" value="@Model.Contact.ContactId" />
<input type="hidden" name="status" value="@ContactStatus.Approved" />
<button type="submit" class="btn btn-xs btn-success">Approve</button>
</form>
}
}
@if (Model.Contact.Status != ContactStatus.Rejected)
{
@if ((await AuthorizationService.AuthorizeAsync(
User, Model.Contact, ContactOperations.Reject)).Succeeded)
{
<form style="display:inline;" method="post">
<input type="hidden" name="id" value="@Model.Contact.ContactId" />
<input type="hidden" name="status" value="@ContactStatus.Rejected" />
<button type="submit" class="btn btn-xs btn-danger">Reject</button>
</form>
}
}
<div>
@if ((await AuthorizationService.AuthorizeAsync(
User, Model.Contact,
ContactOperations.Update)).Succeeded)
{
<a asp-page="./Edit" asp-route-id="@Model.Contact.ContactId">Edit</a>
<text> | </text>
}
<a asp-page="./Index">Back to List</a>
</div>
Ayrıntılar sayfası modelini güncelleştirin:
public class DetailsModel : DI_BasePageModel
{
public DetailsModel(
ApplicationDbContext context,
IAuthorizationService authorizationService,
UserManager<IdentityUser> userManager)
: base(context, authorizationService, userManager)
{
}
public Contact Contact { get; set; }
public async Task<IActionResult> OnGetAsync(int id)
{
Contact = await Context.Contact.FirstOrDefaultAsync(m => m.ContactId == id);
if (Contact == null)
{
return NotFound();
}
var isAuthorized = User.IsInRole(Constants.ContactManagersRole) ||
User.IsInRole(Constants.ContactAdministratorsRole);
var currentUserId = UserManager.GetUserId(User);
if (!isAuthorized
&& currentUserId != Contact.OwnerID
&& Contact.Status != ContactStatus.Approved)
{
return Forbid();
}
return Page();
}
public async Task<IActionResult> OnPostAsync(int id, ContactStatus status)
{
var contact = await Context.Contact.FirstOrDefaultAsync(
m => m.ContactId == id);
if (contact == null)
{
return NotFound();
}
var contactOperation = (status == ContactStatus.Approved)
? ContactOperations.Approve
: ContactOperations.Reject;
var isAuthorized = await AuthorizationService.AuthorizeAsync(User, contact,
contactOperation);
if (!isAuthorized.Succeeded)
{
return Forbid();
}
contact.Status = status;
Context.Contact.Update(contact);
await Context.SaveChangesAsync();
return RedirectToPage("./Index");
}
}
Bir role kullanıcı ekleme veya bir rolden kullanıcı çıkarma
Aşağıdaki konular hakkında bilgi için bkz. bu konu:
- Bir kullanıcıdan ayrıcalıkları kaldırma. Örneğin, sohbet uygulamasında kullanıcının sesini kapatma.
- Kullanıcıya ayrıcalık ekleme.
Sınama ve Yasak arasındaki farklar
Bu uygulama, varsayılan ilkeyi kimliği doğrulanmış kullanıcılar gerektirecek şekilde ayarlar. Aşağıdaki kod anonim kullanıcılara izin verir. Anonim kullanıcıların Sınama ve Yasak arasındaki farkları göstermesine izin verilir.
[AllowAnonymous]
public class Details2Model : DI_BasePageModel
{
public Details2Model(
ApplicationDbContext context,
IAuthorizationService authorizationService,
UserManager<IdentityUser> userManager)
: base(context, authorizationService, userManager)
{
}
public Contact Contact { get; set; }
public async Task<IActionResult> OnGetAsync(int id)
{
Contact = await Context.Contact.FirstOrDefaultAsync(m => m.ContactId == id);
if (Contact == null)
{
return NotFound();
}
if (!User.Identity.IsAuthenticated)
{
return Challenge();
}
var isAuthorized = User.IsInRole(Constants.ContactManagersRole) ||
User.IsInRole(Constants.ContactAdministratorsRole);
var currentUserId = UserManager.GetUserId(User);
if (!isAuthorized
&& currentUserId != Contact.OwnerID
&& Contact.Status != ContactStatus.Approved)
{
return Forbid();
}
return Page();
}
}
Önceki kodda:
- Kullanıcının kimliği doğrulanmadığında bir hata mesajı döndürülür. döndürülürse, kullanıcı oturum açma sayfasına yönlendirilir.
- Kullanıcının kimliği doğrulandığında ancak yetkilendirilmediğinde bir yanıt döndürülür. Bir
ForbidResultdöndürülürse, kullanıcı erişim reddedildi sayfasına yönlendirilir.
Tamamlanan uygulamayı test edin
Yerleşik kullanıcı hesapları için henüz bir parola ayarlamadıysanız, Gizli Yönetici aracını kullanarak bir parola ayarlayın:
Güçlü bir parola seçin: Sekiz veya daha fazla karakter ve en az bir büyük harf karakter, sayı ve simge kullanın. Örneğin, güçlü parola gereksinimlerini karşılar.
project klasöründen aşağıdaki komutu yürütür; burada
<PW>paroladır:dotnet user-secrets set SeedUserPW <PW>
Uygulamanın kişileri varsa:
- Tablodaki tüm kayıtları silin.
- Veritabanının tohumunu oluşturmak için uygulamayı yeniden başlatın.
Tamamlanmış uygulamayı test etmenin kolay bir yolu, üç farklı tarayıcı (veya gizli/InPrivate oturumları) başlatmaktır. Bir tarayıcıda yeni bir kullanıcı kaydedin (örneğin, ). Her tarayıcıda farklı bir kullanıcıyla oturum açın. Aşağıdaki işlemleri doğrulayın:
- Kayıtlı kullanıcılar, onaylanan tüm iletişim verilerini görüntüleyebilir.
- Kayıtlı kullanıcılar kendi verilerini düzenleyebilir/silebilir.
- Yöneticiler iletişim verilerini onaylayabilir/reddedebilir. Görünümde Onayla ve Reddet düğmeleri gösterilir.
- Yöneticiler tüm verileri onaylayabilir/reddedebilir ve düzenleyebilir/silebilir.
| User | Uygulama tarafından dağıtılan | Options |
|---|---|---|
| test@example.com | No | Kendi verileri düzenleyin/silin. |
| manager@contoso.com | Yes | Kendi verilerini onaylayın/reddedin ve düzenleyin/silin. |
| admin@contoso.com | Yes | Tüm verileri onaylayın/reddedin ve düzenleyin/silin. |
Yöneticinin tarayıcısında bir iletişim oluşturun. Yönetici iletişim bilgisinden silme ve değiştirme URL'sini kopyalayın. Test kullanıcısının bu işlemleri gerçekleştiremadığını doğrulamak için bu bağlantıları test kullanıcısının tarayıcısına yapıştırın.
Başlangıç uygulamasını oluşturma
"ContactManager" adlı bir Pages uygulaması oluşturma
- Bireysel Hesaplar ile uygulamayı oluşturun.
- Ad alanının örnekte kullanılan ad alanıyla eşleşmesi için "ContactManager" olarak adlandırın.
- SQLite yerine LocalDB belirtir
dotnet new webapp -o ContactManager -au Individual -uldEkle :
public class Contact { public int ContactId { get; set; } public string Name { get; set; } public string Address { get; set; } public string City { get; set; } public string State { get; set; } public string Zip { get; set; } [DataType(DataType.EmailAddress)] public string Email { get; set; } }Modelin iskelesini oluşturma .
İlk geçişi oluşturun ve veritabanını güncelleştirin:
dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design
dotnet tool install -g dotnet-aspnet-codegenerator
dotnet aspnet-codegenerator razorpage -m Contact -udl -dc ApplicationDbContext -outDir Pages\Contacts --referenceScriptLibraries
dotnet ef database drop -f
dotnet ef migrations add initial
dotnet ef database update
Note
Varsayılan olarak yüklenecek .NET ikili dosyalarının mimarisi şu anda çalışan işletim sistemi mimarisini temsil eder. Farklı bir işletim sistemi mimarisi belirtmek için bkz . dotnet tool install, --arch option. Daha fazla bilgi için bkz. GitHub sorun dotnet/AspNetCore.Docs #29262.
dotnet aspnet-codegenerator razorpage komutuyla ilgili bir hatayla karşılaşırsanız bkz. bu GitHub sorunu.
- Dosyadaki ContactManager tutturucuyu güncelleştirin :
<a class="navbar-brand" asp-area="" asp-page="/Contacts/Index">ContactManager</a>
- Kişi oluşturarak, düzenleyerek ve silerek uygulamayı test edin
Veritabanının tohumunu oluşturma
SeedData sınıfını Data klasörüne ekleyin:
using ContactManager.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Linq;
using System.Threading.Tasks;
// dotnet aspnet-codegenerator razorpage -m Contact -dc ApplicationDbContext -udl -outDir Pages\Contacts --referenceScriptLibraries
namespace ContactManager.Data
{
public static class SeedData
{
public static async Task Initialize(IServiceProvider serviceProvider, string testUserPw)
{
using (var context = new ApplicationDbContext(
serviceProvider.GetRequiredService<DbContextOptions<ApplicationDbContext>>()))
{
SeedDB(context, "0");
}
}
public static void SeedDB(ApplicationDbContext context, string adminID)
{
if (context.Contact.Any())
{
return; // DB has been seeded
}
context.Contact.AddRange(
new Contact
{
Name = "Debra Garcia",
Address = "1234 Main St",
City = "Redmond",
State = "WA",
Zip = "10999",
Email = "debra@example.com"
},
new Contact
{
Name = "Thorsten Weinrich",
Address = "5678 1st Ave W",
City = "Redmond",
State = "WA",
Zip = "10999",
Email = "thorsten@example.com"
},
new Contact
{
Name = "Yuhong Li",
Address = "9012 State st",
City = "Redmond",
State = "WA",
Zip = "10999",
Email = "yuhong@example.com"
},
new Contact
{
Name = "Jon Orton",
Address = "3456 Maple St",
City = "Redmond",
State = "WA",
Zip = "10999",
Email = "jon@example.com"
},
new Contact
{
Name = "Diliana Alexieva-Bosseva",
Address = "7890 2nd Ave E",
City = "Redmond",
State = "WA",
Zip = "10999",
Email = "diliana@example.com"
}
);
context.SaveChanges();
}
}
}
Çağrı şuradan:
using ContactManager.Data;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
namespace ContactManager
{
public class Program
{
public static void Main(string[] args)
{
var host = CreateHostBuilder(args).Build();
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
try
{
var context = services.GetRequiredService<ApplicationDbContext>();
context.Database.Migrate();
SeedData.Initialize(services, "not used");
}
catch (Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred seeding the DB.");
}
}
host.Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}
Uygulamanın veritabanını doldurduğunu test edin. İletişim veritabanında herhangi bir satır varsa, seed yöntemi çalışmaz.
Ek kaynaklar
- Öğretici: Azure App Service'te ASP.NET Core ve Azure SQL Veritabanı uygulaması oluşturma
- ASP.NET Core Yetkilendirme Laboratuvarı. Bu laboratuvar, bu öğreticide sunulan güvenlik özellikleri hakkında daha ayrıntılı bilgi verir.
ASP.NET Core - Özel ilke tabanlı yetkilendirme
ASP.NET Core