Авторизация и аутентификация в MVC 5 ASP.NET Identity Релиз ASP.NET MVC 5 ознаменовался выходом новой системой авто- ризации и аутентификации в .NET приложениях под названием ASP.NET Identity. Эта система пришла на смену провайдерам Simple Membership, ко- торые были введены в ASP.NET MVC 4. Рассмотрим систему авторизации и аутентификации ASP.NET Identity на примере приложения MVC 5. Итак, при создании приложения MVC 5 Vis- ual Studio предлагает нам выбрать один из типов аутентификации: Рисунок 1 - Окно Change Authentication Нажав на кнопку Change Authentication, мы можем изменить тип аутен- тификации, выбрав одно из следующих: No Authentication: ASP.NET Identity и встроенная система аутен- тификации отсутствует;
31
Embed
Авторизация и аутентификация в MVC 5portal.tpu.ru/SHARED/m/MARTYNOVYAA/study_work/stud...Авторизация и аутентификация в MVC 5
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Авторизация и аутентификация в MVC 5
ASP.NET Identity
Релиз ASP.NET MVC 5 ознаменовался выходом новой системой авто-
ризации и аутентификации в .NET приложениях под названием ASP.NET
Identity. Эта система пришла на смену провайдерам Simple Membership, ко-
торые были введены в ASP.NET MVC 4.
Рассмотрим систему авторизации и аутентификации ASP.NET Identity
на примере приложения MVC 5. Итак, при создании приложения MVC 5 Vis-
ual Studio предлагает нам выбрать один из типов аутентификации:
Рисунок 1 - Окно Change Authentication
Нажав на кнопку Change Authentication, мы можем изменить тип аутен-
тификации, выбрав одно из следующих:
No Authentication: ASP.NET Identity и встроенная система аутен-
тификации отсутствует;
Individual User Accounts: проект по умолчанию включает систему
ASP.NET Identity, которая позволяет авторизовать как пользова-
телей внутри приложения, так и с помощью внешних сервисов,
как google, твиттер и т.д.;
Organizational Accounts: подходит для сайтов и веб-приложений
отдельных компаний и организаций;
Windows Authentication: система аутентификации для сетей intra-
net с помощью учетных записей Windows.
Оставим значение по умолчанию, то есть Individual User Accounts и со-
здадим проект.
Созданный проект уже по умолчанию имеет всю необходимую для ав-
торизации инфраструктуру: модели, контроллеры, представления. Если мы
заглянем в узел References (Библиотеки), то увидим там ряд ключевых биб-
лиотек, которые и содержит необходимые для авторизации и аутентифика-
ции классы:
Рисунок 2 - Библиотеки для аутентификации через ASP.NET Identity
Это ряд библиотек OWIN, которые добавляют функциональность
OWIN в проект, а также три библиотеки собственно ASP.NET Identity:
Microsoft.AspNet.Identity.EntityFramework: содержит классы Enti-
ty Framework, применяющие ASP.NET Identity и осуществляю-
щие связь с SQL Serveroм;
Microsoft.AspNet.Identity.Core: содержит ряд ключевых интер-
фейсов ASP.NET Identity. Реализация этих интерфейсов позволит
выйти за рамки MS SQL Server и использовать в качестве храни-
лища учетных записей другие СУБД, в том числе системы
NoSQL;
Microsoft.AspNet.Identity.OWIN: привносит в приложение
ASP.NET MVC аутентификацию OWIN с помощью ASP.NET
Identity.
Поскольку вся инфраструктура уже имеется в проекте, запустим про-
ект, на отобразившейся в браузере странице найдем ссылку Register и
нажмем на нее. На открывшейся странице регистрации введем какие-нибудь
данные:
Рисунок 3 - Регистрация через ASP.NET Identity
После регистрации логин будет отображаться в правом верхнем углу
веб-страницы веб-приложения. Осуществив регистрацию, мы можем разло-
гиниться, нажав на LogOff, и снова войти в систему. Таким образом, мы мо-
жем уже начать пользоваться встроенной системой аутентификации в при-
ложении ASP.NET MVC 5. Теперь же рассомотрим ее основные моменты.
Во-первых, где это все хранится? Куда попадают данные зарегистриро-
ванных пользователей?
В данном случае используется подход Code First. В файле web.config
уже имеется строка подключения по умолчанию, которая задает каталог базы
данных. Если мы раскроем папку App_Data, то сможем увидеть созданную
базу данных:
Рисунок 4 - База данных по умолчанию
Если вдруг в папке база данных не видна, нажмем вверху окна Solution
Explorer на кнопку Show All Files (Показать все файлы).
Мы можем открыть эту базу данных в окне Server Explorer и увидеть ее
содержимое:
Рисунок 5 - База данных в ASP.NET Identity
По умолчанию при регистрации первого пользователя создается сле-
дующий набор таблиц:
_MigrationHistory: используется EntityFramework для миграций
БД;
AspNetRoles: содержит определения ролей;
AspNetUserClaims: таблица, хранящая набор клеймов (claim).
Claim представляет иную модель авторизации по сравнению с
ролями. Грубо говоря, claim содержит некоторую информацию о
пользователе, например, адрес электронной почты, логин, воз-
раст и т.д. И эта информация позволяет идентифицировать поль-
зователя и наделить его соответствующими правами доступа;
AspNetUserLogins: таблица логинов пользователя;
AspNetUserRoles: таблица, устанавливающая для пользователей
определенные роли;
AspNetUsers: собственно таблица пользователей. Если мы ее от-
кроем, то увидим данные зарегистрированного пользователя.
Ключевыми объектами в AspNet Identity являются пользователи и роли.
Вся функциональность по созданию, удалению пользователей, взаимодей-
ствию с хранилищем пользователей хранится в классе UserManager. Для ра-
боты с ролями и их управлением в AspNet Identity определен класс
RoleManager. Классы UserManager и RoleManager находятся в библиотеке
Теперь добавим классы пользователей и контекста данных в папку
Models. Класс контекста будет наследоваться от IdentityDbContext:
using System.Data.Entity;
using Microsoft.AspNet.Identity.EntityFramework;
public class ApplicationContext : IdentityDbContext<ApplicationUser> { public ApplicationContext() : base("IdentityDb") { } public static ApplicationContext Create() { return new ApplicationContext(); } }
Класс пользователей:
using Microsoft.AspNet.Identity.EntityFramework; public class ApplicationUser : IdentityUser { public int Year { get; set; } public ApplicationUser()
{ } }
В классе пользователя кроме унаследованных от IdentityUser свойств
также определяется и свойство Year для хранения года рождения пользовате-
ля.
Поскольку вся работа с пользователями идет не напрямую, а через ме-
неджер пользователей, то также добавим в папку Models соответствующий
класс:
using Microsoft.AspNet.Identity; using Microsoft.AspNet.Identity.EntityFramework; using Microsoft.AspNet.Identity.Owin; using Microsoft.Owin; public class ApplicationUserManager : UserManager<ApplicationUser> { public ApplicationUserManager(IUserStore<ApplicationUser> store) : base(store) { } public static ApplicationUserManager Create (IdentityFactoryOp-tions<ApplicationUserManager> options, IOwinContext context) { ApplicationContext db = context.Get<ApplicationContext>(); ApplicationUserManager manager = new ApplicationUserManager(new Us-erStore<ApplicationUser>(db)); return manager; } }
Класс менеджера пользователей наследуется от UserManager. В кон-
структоре он принимает объект хранилища пользователей IUserStore. А ста-
тический метод Create() создает экземпляр класса ApplicationUserManager с
помощью объекта контекстаIOwinContext
Последний шаг в первоначальной настройке проекта для AspNet
Identity состоит в добавлении в проект файла запуска приложения OWIN.
Итак, добавим в папку App_Start файл Startup.cs со следующим содержани-
ем:
using Microsoft.Owin; using Owin; using AspNetIdentityApp.Models; using Microsoft.Owin.Security.Cookies; using Microsoft.AspNet.Identity; [assembly: OwinStartup(typeof(AspNetIdentityApp.Startup))] namespace AspNetIdentityApp {
public class Startup { public void Configuration(IAppBuilder app) { // настраиваем контекст и менеджер
Types.ApplicationCookie, LoginPath = new PathString("/Account/Login"), }); } } }
Интерфейс IAppBuilder определяет множество методов, в данном случае
нам достаточно трех методов. МетодCreatePerOwinContext регистрирует в
OWIN менеджер пользователей ApplicationUserManager и класс контекста
ApplicationContext.
Метод UseCookieAuthentication с помощью объекта
CookieAuthenticationOptions устанавливает аутентификацию на основе куки в
качестве типа аутентификации в приложении. А свойство LoginPath позволяет
установить адрес URL, по которому будут перенаправляться неавторизован-
ные пользователи. Как правило, это адрес /Account/Login.
Это минимально необходимая настройка проекта для использования
AspNet Identity, на основе которой мы уже сможем создавать всю остальную
систему авторизации и аутентификации.
Регистрация и создание пользователей в ASP.NET
Identity
Продолжим работу с проектом из прошлой темы и добавим в него
функционал регистрации пользователей.
Класс IdentityUser определяет множество свойств, однако нам необяза-
тельно всех их устанавливать. И в данном случае для создания пользователей
нам лучше воспользоваться связующей моделью, которая установит все не-
обходимые свойства. Итак, добавим в папку Models класс, который будет
представлять пользователя:
using System; using System.ComponentModel.DataAnnotations; namespace AspNetIdentityApp.Models { public class RegisterModel { [Required] public string Email { get; set; } [Required] public int Year { get; set; } [Required] [DataType(DataType.Password)] public string Password { get; set; } [Required] [Compare("Password", ErrorMessage = "Пароли не совпадают")] [DataType(DataType.Password)] public string PasswordConfirm { get; set; } } }
Теперь добавим в папку Controllers новый контроллер AccountControl-
ler:
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.Web; using System.Web.Mvc; using AspNetIdentityApp.Models; using Microsoft.AspNet.Identity; using Microsoft.AspNet.Identity.Owin; namespace AspNetIdentityApp.Controllers { public class AccountController : Controller { private ApplicationUserManager UserManager { get { return HttpCon-text.GetOwinContext().GetUserManager<ApplicationUserManager>(); } } public ActionResult Register() { return View(); } [HttpPost] public async Task<ActionResult> Register(RegisterModel model)
{ if (ModelState.IsValid) { ApplicationUser user = new ApplicationUser { UserName = mod-el.Email, Email = model.Email, Year = model.Year }; IdentityResult result = await UserManager.CreateAsync(user,
Сущность ролей в ASP.NET Identity представлена классом IdentityRole,
который реализует интерфейс IRole. И мы можем продолжать использовать
IdentityRole, но при необходимости также можем переопределить, добавив в
него новые свойства. Итак, возьмем проект из прошлой темы и добавим в не-
го функциональность управления ролями.
Для начала добавим в папку Models новый класс ApplicationRole:
using Microsoft.AspNet.Identity.EntityFramework; public class ApplicationRole: IdentityRole { public ApplicationRole(){} public string Description { get; set; } }
Новый класс наследует весь функционал от IdentityRole плюс добавля-
ет новое свойство Description, которое будет содержать описание роли.
Для управления ролями используется менеджер ролей RoleManager.
Поэтому добавим в папку Models новый класс ApplicationRoleManager:
class ApplicationRoleManager : RoleManager<ApplicationRole> { public ApplicationRoleManager(RoleStore<ApplicationRole> store) : base(store) {} public static ApplicationRoleManager Cre-ate(IdentityFactoryOptions<ApplicationRoleManager> options, IOwinContext context) { return new ApplicationRoleManager(new
Types.ApplicationCookie, LoginPath = new PathString("/Account/Login"), }); } }
Благодаря регистрации менеджер ролей будет использовать тот же кон-
текст данных, что и менеджер пользователей.
Если мы создаем систему ролей в приложении после первого запуска
приложения, то нам надо будет произвести миграцию, так как контекст дан-
ных у нас изменился в силу изменения системы ролей. Поэтому в Visual Stu-
dio в окне Package Manager Console введем команду: enable-migrations и
нажмем Enter.
Теперь нам надо создать саму миграцию. Там же в консоли Package
Manager Console введем команду:
PM> Add-Migration "DataMigration"
Visual Studio автоматически сгенерирует класс миграции:
public partial class DataMigration : DbMigration { public override void Up() { AddColumn("dbo.AspNetRoles", "Description", c => c.String()); AddColumn("dbo.AspNetRoles", "Discriminator", c => c.String(nullable:
И чтобы выполнить миграцию, применим этот класс, набрав в той же
консоли команду:
PM> Update-Database
Теперь создадим контроллер, который будет выполнять стандартные
действия с ролями:
using AspNetIdentityApp.Models; using Microsoft.AspNet.Identity; using Microsoft.AspNet.Identity.Owin; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.Web; using System.Web.Mvc; public class RolesController : Controller { private ApplicationRoleManager RoleManager { get { return HttpCon-text.GetOwinContext().GetUserManager<ApplicationRoleManager>(); } } public ActionResult Index() { return View(RoleManager.Roles); } public ActionResult Create() { return View(); } [HttpPost] public async Task<ActionResult> Create(CreateRoleModel model) { if (ModelState.IsValid) { IdentityResult result = await RoleManager.CreateAsync(new Applica-tionRole { Name = model.Name, Description = model.Description }); if (result.Succeeded) { return RedirectToAction("Index"); } else { ModelState.AddModelError("", "Что-то пошло не так"); } } return View(model);
} public async Task<ActionResult> Edit(string id) { ApplicationRole role = await RoleManager.FindByIdAsync(id); if (role != null) { return View(new EditRoleModel { Id = role.Id, Name = role.Name, Description = role.Description }); } return RedirectToAction("Index"); } [HttpPost] public async Task<ActionResult> Edit(EditRoleModel model) { if (ModelState.IsValid) { ApplicationRole role = await RoleManager.FindByIdAsync(model.Id); if (role != null) { role.Description = model.Description; role.Name = model.Name; IdentityResult result = await RoleManager.UpdateAsync(role); if (result.Succeeded) { return RedirectToAction("Index"); } else { ModelState.AddModelError("", "Что-то пошло не так"); } } } return View(model); } public async Task<ActionResult> Delete(string id) { ApplicationRole role = await RoleManager.FindByIdAsync(id); if (role != null) { IdentityResult result = await RoleManager.DeleteAsync(role); } return RedirectToAction("Index"); } }
Это стандартный CRUD-контроллер, выполняющий чтение, удаление,
редактирование и добавление ролей. Вначале для взаимодействия с менедже-
ром ролей мы получаем его объект из контекста OWIN:
Затем методы менеджера ролей используются для управления ролями.
Обратите внимание, что из представлений в методы Create и Edit мы получа-
ем не объект ApplicationRole, а специальные модели EditRoleModel и
CreateRoleModel, который могут выглядеть так:
public class EditRoleModel { public string Id { get; set; } public string Name { get; set; } public string Description { get; set; } } public class CreateRoleModel { public string Name { get; set; } public string Description { get; set; } }
Использование моделей позволит избежать различных проблем с кон-
текстом данных и управлением объектами, которые могли возникнуть, если
бы мы напрямую использовали бы ApplicationRole.
И представления будут выглядеть стандартно. Представление In-