Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core
Ранее мы рассмотрели создание трехуровневой архитектуры приложения. Тепеь рассмотрим, как мы можем использовать в этой архитектуре встроенную систему аутентификации и авторизации ASP.NET Identity.
Итак, создадим новое решение. Пусть оно будет называться UserStore и в этом решении определим новый проект UserStore.WEB по типу ASP.NET MVC 5 без аутентификации.
После этого добавим в решение новый проект по типу Class Library, который назовем UserStore.DAL. Этот проект будет представлять слой доступа к данным.
Так как мы будем использовать систему ASP.NET Identity, то нам вначале надо добавить соответствующие пакеты NuGet: EntityFramework, Microsoft.AspNet.Identity.Core и Microsoft.AspNet.Identity.EntityFramework
Вначале добавим в DAL-проект новую папку, которую назовем Entities. В этой папке будут храниться сущности приложения. В данном случае ограничимся тремя сущностями: классом пользователя, классом роли и классом профиля пользователя.
Итак, добавим в папку Entities новый класс ApplicationUser:
using Microsoft.AspNet.Identity.EntityFramework; namespace UserStore.DAL.Entities { public class ApplicationUser : IdentityUser { public virtual ClientProfile ClientProfile { get; set; } } }
И также добавим класс профиля пользователя ClientProfile:
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace UserStore.DAL.Entities { public class ClientProfile { [Key] [ForeignKey("ApplicationUser")] public string Id { get; set; } public string Name { get; set; } public string Address { get; set; } public virtual ApplicationUser ApplicationUser { get; set; } } }
Класс пользователя и его профиля связаны отношением один-к-одному. Разделение данных о пользователя на два класса позволит независимо друг от друга рассматривать аутентификационные данные и вспомогательные данные, то есть профиль пользователя, которые не играют никакой роли при аутентификации.
И также добавим в эту папку класс роли ApplicationRole:
using Microsoft.AspNet.Identity.EntityFramework; namespace UserStore.DAL.Entities { public class ApplicationRole : IdentityRole { } }
Важно отметить, что эти классы зависят от пространства имен Microsoft.AspNet.Identity.EntityFramework.
Далее добавим в проект новую папку, которую назовем EF и в которую поместим новый класс ApplicationContext, то есть контекст данных:
using System.Data.Entity; using Microsoft.AspNet.Identity.EntityFramework; using UserStore.DAL.Entities; namespace UserStore.DAL.EF { public class ApplicationContext: IdentityDbContext<ApplicationUser> { public ApplicationContext(string conectionString) : base(conectionString) { } public DbSet<ClientProfile> ClientProfiles { get; set; } } }
Данный класс наследуется от класса IdentityDbContext и поэтому уже имеет свойства Users и Roles, позволяющие взаимодействовать с таблицами пользователей и ролей. Поэтому здесь мы добавляем только свойство для ClientProfile.
Теперь добавим в проект еще три папки: Identity, Interfaces и Repositories. В папку Identity добавим класс ApplicationUserManager:
using UserStore.DAL.Entities; using Microsoft.AspNet.Identity; namespace UserStore.DAL.Identity { public class ApplicationUserManager : UserManager<ApplicationUser> { public ApplicationUserManager(IUserStore<ApplicationUser> store) : base(store) { } } }
Данный класс будет управлять пользователями: добавлять их в базу данных и аутентифицировать.
Также добавим в папку Identity новый класс ApplicationRoleManager:
using UserStore.DAL.Entities; using Microsoft.AspNet.Identity; using Microsoft.AspNet.Identity.EntityFramework; namespace UserStore.DAL.Identity { public class ApplicationRoleManager : RoleManager<ApplicationRole> { public ApplicationRoleManager(RoleStore<ApplicationRole> store) : base(store) { } } }
Это стандартные для ASP.NET Identity классы по управлению ролями и пользователями. По сути эти классы выполняют роль репозиториев.
В папку Interfaces добавим интерфейс управления профилями пользователей IClientManager:
using UserStore.DAL.Entities; using System; namespace UserStore.DAL.Interfaces { public interface IClientManager:IDisposable { void Create(ClientProfile item); } }
Данный интерфейс содержит один метод для создания нового профиля пользователя.
И также определим интерфейс для UnitOfWork:
using UserStore.DAL.Identity; using System; using System.Threading.Tasks; namespace UserStore.DAL.Interfaces { public interface IUnitOfWork : IDisposable { ApplicationUserManager UserManager { get; } IClientManager ClientManager { get; } ApplicationRoleManager RoleManager { get; } Task SaveAsync(); } }
Объект UnitOfWork будет содержать ссылки на менеджеры пользователей и ролей, а также на репозиторий пользователей.
В папку Repositories добавим два класса - конкретные реализации этих интерфейсов. Класс управления профилями ClientManager:
using UserStore.DAL.EF; using UserStore.DAL.Entities; using UserStore.DAL.Interfaces; namespace UserStore.DAL.Repositories { public class ClientManager : IClientManager { public ApplicationContext Database { get; set; } public ClientManager(ApplicationContext db) { Database = db; } public void Create(ClientProfile item) { Database.ClientProfiles.Add(item); Database.SaveChanges(); } public void Dispose() { Database.Dispose(); } } }
И класс IdentityUnitOfWork:
using UserStore.DAL.EF; using UserStore.DAL.Entities; using UserStore.DAL.Interfaces; using Microsoft.AspNet.Identity.EntityFramework; using System; using System.Threading.Tasks; using UserStore.DAL.Identity; namespace UserStore.DAL.Repositories { public class IdentityUnitOfWork : IUnitOfWork { private ApplicationContext db; private ApplicationUserManager userManager; private ApplicationRoleManager roleManager; private IClientManager clientManager; public IdentityUnitOfWork(string connectionString) { db = new ApplicationContext(connectionString); userManager = new ApplicationUserManager(new UserStore<ApplicationUser>(db)); roleManager = new ApplicationRoleManager(new RoleStore<ApplicationRole>(db)); clientManager = new ClientManager(db); } public ApplicationUserManager UserManager { get { return userManager; } } public IClientManager ClientManager { get { return clientManager; } } public ApplicationRoleManager RoleManager { get { return roleManager; } } public async Task SaveAsync() { await db.SaveChangesAsync(); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } private bool disposed = false; public virtual void Dispose(bool disposing) { if (!this.disposed) { if (disposing) { userManager.Dispose(); roleManager.Dispose(); clientManager.Dispose(); } this.disposed = true; } } } }
Класс инкапсулирует все менеджеры для работы с сущностями в виде свойств и хранит общий контекст данных.
В итоге проект будет выглядеть следующим образом: