Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core 7
Создадим новый проект ASP.NET Core по типу WebApplication (Model-View-Controller), который назовем ClaimsApp.
Затем добавим в проект новую папку для моделей, которую назовем Models. И определим в этой папке класс пользователя:
public class User { public int Id { get; set; } public string Email { get; set; } public string Password { get; set; } public string City { get; set; } public string Company { get; set; } public int Year { get; set; } }
Для взаимодействия с MS SQL Server через Entity Framework добавим в проект через Nuget пакет Microsoft.EntityFrameworkCore.SqlServer. И также добавим в папку Models новый класс ApplicationContext, который будет представлять контекст данных:
using Microsoft.EntityFrameworkCore; namespace ClaimsApp.Models { public class ApplicationContext : DbContext { public DbSet<User> Users { get; set; } public ApplicationContext(DbContextOptions<ApplicationContext> options) : base(options) { Database.EnsureCreated(); } } }
Теперь изменим класс Startup для установки и использования контекста данных:
using System.Security.Claims; using ClaimsApp.Models; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Builder; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; namespace ClaimsApp { public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } public void ConfigureServices(IServiceCollection services) { string connection = "Server=(localdb)\mssqllocaldb;Database=claimsstoredb;Trusted_Connection=True;"; services.AddDbContext<ApplicationContext>(options => options.UseSqlServer(connection)); services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(options => { options.LoginPath = new Microsoft.AspNetCore.Http.PathString("/Account/Register"); }); services.AddAuthorization(opts => { opts.AddPolicy("OnlyForLondon", policy => { policy.RequireClaim(ClaimTypes.Locality, "Лондон", "London"); }); opts.AddPolicy("OnlyForMicrosoft", policy => { policy.RequireClaim("company", "Microsoft"); }); }); services.AddControllersWithViews(); } public void Configure(IApplicationBuilder app) { app.UseDeveloperExceptionPage(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); }); } } }
Здесь устанавливаются две политики - "OnlyForLondon" и "OnlyForMicrosoft". Первая политика требует, чтобы claim с типом ClaimTypes.Locality
имел значение "London" или "Лондон". Если значений много, то мы их можем перечислить через запятую. Вторая политика требует наличия Claim с типом
"company" и значением "Microsoft".
Для тестирования авторизации добавим в папку Controllers новый контроллер AccountController, который будет выполнять регистрацию пользователей.
Для регистрации определим в папке Models дополнительную модель RegisterModel:
using System.ComponentModel.DataAnnotations; namespace ClaimsApp.Models { public class RegisterModel { [Required(ErrorMessage = "Не указан Email")] public string Email { get; set; } [Required(ErrorMessage = "Не указан пароль")] [DataType(DataType.Password)] public string Password { get; set; } [DataType(DataType.Password)] [Compare("Password", ErrorMessage = "Пароль введен неверно")] public string ConfirmPassword { get; set; } public string City { get; set; } public string Company { get; set; } public int Year { get; set; } } }
И также для представлений контроллера добавим в папку Views подкаталог Account и поместим в него новое представление Register.cshtml:
@model ClaimsApp.Models.RegisterModel <h2>Регистрация</h2> <form asp-action="Register" asp-controller="Account" asp-anti-forgery="true"> <div class="validation" asp-validation-summary="All"></div> <div> <div> <label asp-for="Email">Введите Email</label><br /> <input type="text" asp-for="Email" /> </div> <div> <label asp-for="Password">Введите пароль</label><br /> <input asp-for="Password" /> </div> <div> <label asp-for="ConfirmPassword">Повторите пароль</label><br /> <input asp-for="ConfirmPassword" /> </div> <div> <label asp-for="City">Введите город</label><br /> <input type="text" asp-for="City" /> </div> <div> <label asp-for="Company">Введите компанию</label><br /> <input type="text" asp-for="Company" /> </div> <div> <label asp-for="Year">Введите год рождения</label><br /> <input type="text" asp-for="Year" /> </div> <div> <input type="submit" value="Регистрация" /> </div> </div> </form>
А в контроллере AccountController определим действие регистрации:
using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using ClaimsApp.Models; using Microsoft.EntityFrameworkCore; using System.Security.Claims; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Cookies; namespace ClaimsApp.Controllers { public class AccountController : Controller { private ApplicationContext _context; public AccountController(ApplicationContext context) { _context = context; } [HttpGet] public IActionResult Register() { return View(); } [HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> Register(RegisterModel model) { if (ModelState.IsValid) { User user = await _context.Users.FirstOrDefaultAsync(u => u.Email == model.Email); if (user == null) { // добавляем пользователя в бд user = new User { Email = model.Email, Password = model.Password, Year = model.Year, City = model.City, Company = model.Company }; _context.Users.Add(user); await _context.SaveChangesAsync(); await Authenticate(user); return RedirectToAction("Index", "Home"); } else ModelState.AddModelError("", "Некорректные логин и(или) пароль"); } return View(model); } private async Task Authenticate(User user) { // создаем один claim var claims = new List<Claim> { new Claim(ClaimsIdentity.DefaultNameClaimType, user.Email), new Claim(ClaimTypes.Locality, user.City), new Claim("company", user.Company) }; // создаем объект ClaimsIdentity ClaimsIdentity id = new ClaimsIdentity(claims, "ApplicationCookie", ClaimsIdentity.DefaultNameClaimType, ClaimsIdentity.DefaultRoleClaimType); // установка аутентификационных куки await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(id)); } } }
В итоге весь проект будет выглядеть следующим образом:
Для тестирования доступа изменим контроллер HomeController:
public class HomeController : Controller { [Authorize(Policy ="OnlyForLondon")] public IActionResult Index() { return View(); } [Authorize(Policy = "OnlyForMicrosoft")] public IActionResult About() { return Content("Only for Microsoft employees"); } }
Здесь метод Index
доступен только для тех пользователей, которые удовлетворяют политике "OnlyForLondon", а метод About - для пользователей,
соответствующих политике "OnlyForMicrosoft".
И пусть в представлении для метода Index контроллера Home выводятся все объекты Claim для текущего пользователя:
@using System.Security.Claims @foreach(var claim in User.Claims.ToList()) { <p>@claim.Type : @claim.Value</p> } <div>Город: @User.FindFirst(x => x.Type == ClaimTypes.Locality).Value</div> <div>Компания: @User.FindFirst(x => x.Type == "company").Value</div>
Запустим проект и зарегистрируем нового пользователя:
И после регистрации перейдем к методу Index контроллера HomeController: