Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core
Инструмент Claims в рамках ASP.NET Identity представляет нам прекрасный способ для создания системы авторизации, которая основана на самых различных свойствах объекта или так называемая Claims-Based Authorization. Например, если мы хотим разграничить доступ к ресурсам в зависимости от возраста пользователя, то с помощью Claims мы это легко можем сделать.
Итак, создадим новый проект с типом авторизации Individual User Accounts. Пусть нам надо добавить разграничение доступа по возрасту пользователя. Для этого прежде всего изменим подсистему регистрации.
В модель RegisterModel из файла Models/AccountViewModels.cs добавим свойство Year для хранения года рождения пользователя:
public class RegisterViewModel { [Required] [EmailAddress] [Display(Name = "Email")] public string Email { get; set; } [Required] [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; } [Required] [Range(1910, 2015)] [Display(Name = "Year")] public int Year { get; set; } }
И также добавим в представление дл регистрации Register.cshtml код для создания поля ввода года рождения:
<div class="form-group"> @Html.LabelFor(m => m.Year, new { @class = "col-md-2 control-label" }) <div class="col-md-10"> @Html.TextBoxFor(m => m.Year, new { @class = "form-control" }) </div> </div>
Итак, в модели RegisterModel определено свойство Year, а в представлении ля него имеется поле ввода. Теперь изменим post-версию метода Register, чтобы использовать это свойство:
[HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] public async Task<ActionResult> Register(RegisterViewModel model) { if (ModelState.IsValid) { var user = new ApplicationUser { UserName = model.Email, Email = model.Email }; var result = await UserManager.CreateAsync(user, model.Password); if (result.Succeeded) { // создаем claim для хранения года рождения var identityClaim = new IdentityUserClaim { ClaimType = "Year", ClaimValue = model.Year.ToString() }; // добавляем claim пользователю user.Claims.Add(identityClaim); // сохраняем изменения await UserManager.UpdateAsync(user); await SignInManager.SignInAsync(user, isPersistent:false, rememberBrowser:false); return RedirectToAction("Index", "Home"); } AddErrors(result); } return View(model); }
После создания пользователя вначале формируем объект IdentityUserClaim:
var identityClaim = new IdentityUserClaim { ClaimType = "Year", ClaimValue = model.Year.ToString() };
Чтобы задействовать этот класс, надо подключить пространство имен Microsoft.AspNet.Identity.EntityFramework
. Свойство
ClaimType
отвечает за тип данных. Поскольку здесь сохраняется год, то и тип называется Year. А свойство ClaimValue
хранит значение для этого типа в виде строки.
Далее claim добавляется пользователю, и происходит обновление:
user.Claims.Add(identityClaim); await UserManager.UpdateAsync(user);
В итоге claim будет сохранен в базе данных. Для хранения claim в ASP.NET Identity используется таблица AspNetUserClaims. А сохраненые данные будут выглядеть примерно так:
В данном случае определяется claim "Year" для хранения года рождения, но также мы можем сохранять и любую другую информацию о пользователе.
Затем изменим класс ApplicationUser, чтобы он сохранял данные своего claim в куках:
public class ApplicationUser : IdentityUser { public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager) { var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie); var yearClaim = Claims.FirstOrDefault(c => c.ClaimType == "Year"); if (yearClaim != null) userIdentity.AddClaim(new Claim(yearClaim.ClaimType, yearClaim.ClaimValue)); return userIdentity; } }
И в конце нам надо создать атрибут, который бы позволил устанавливать ограничения по доступу. Для этого добавим в проект новую папку Util, и затем в нее добавим новый класс ClaimsAuthorizeAttribute:
using System; using System.Security.Claims; using System.Web; using System.Web.Mvc; namespace AspClaimsApp.Util { public class ClaimsAuthorizeAttribute : AuthorizeAttribute { public int Age { get; set; } protected override bool AuthorizeCore(HttpContextBase httpContext) { ClaimsIdentity claimsIdentity; if (!httpContext.User.Identity.IsAuthenticated) return false; claimsIdentity = httpContext.User.Identity as ClaimsIdentity; var yearClaims = claimsIdentity.FindFirst("Year"); if (yearClaims == null) return false; int year; // получаем год if (!Int32.TryParse(yearClaims.Value, out year)) return false; // проверяем возраст относительно текущей даты if ((DateTime.Now.Year - year) < this.Age) return false; // обращаемся к методу базового класса return base.AuthorizeCore(httpContext); } } }
Данный класс наследуется от атрибута авторизации AuthorizeAttribute и добавляет свойство Age
,
которое позволит устанавливать ограничения по возрасту.
В самом классе с помощью получаемого контекста запроса httpContext извлекаем claim и устанавливаем, имеет ли текущий пользователь
доступ к ресурсу. Если пользователь проходит авторизацию, то возвращается true
, если нет, то false
.
И после этого мы сможем использовать данный атрибут в контроллере. Например:
public class HomeController : Controller { [ClaimsAuthorize(Age=18)] public ActionResult Index() { return View(); } [ClaimsAuthorize(Age = 22)] public ActionResult About() { return View(); } }