Авторизация на основе Claims

Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core

Последнее обновление: 06.12.2015

Инструмент 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. А сохраненые данные будут выглядеть примерно так:

Claims Based Authorization

В данном случае определяется 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();
    }
}
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850