Отделение удостоверения ASP.NET от базовых моделей домена - луковая архитектура

Я использую этот образец проекта (https://github.com/imranbaloch/ASPNETIdentityWithOnion) в качестве архитектуры моего приложения. , в этом примере ядро ​​полностью декодируется из инфраструктуры, включая структуру идентификации.

В этом примере автор использовал шаблон адаптера для разделения основных классов идентификации (IdentityUser, IdentityRole ...) и предоставления таких классов на уровне ядра.

Теперь проблема в этом примере проекта заключается в том, что модель домена (продукт, изображения) не связана с фиктивными классами (AppUser, ApplicationRole, AppliationUserRoles, ...), которые имитируют классы Identity.

Затем я изменил код, добавив ссылку на AppUser.

public sealed class Image : BaseEntity
{
    public Image()
    {
        Products = new HashSet<Product>();
    }

    public string Path { get; set; }

    public AppUser AppUser { get; set; } // The  Added Reference ...

    public ICollection<Product> Products { get; set; }
}

Если я помещу свойство навигации «AppUser» в класс «Image», созданная база данных будет иметь ЧЕТЫРЕ новых таблицы, кроме ПЯТИ таблиц по умолчанию структуры идентификации.

Проблема луковой базы данных с таблицами идентичности

Мне нужно объединить эти таблицы с таблицами по умолчанию. как ?

РЕДАКТИРОВАТЬ:

Это модели идентичности, которые находятся на уровне данных (на которые я не могу ссылаться из ядра).

public class ApplicationIdentityUser :
    IdentityUser<int, ApplicationIdentityUserLogin, ApplicationIdentityUserRole, ApplicationIdentityUserClaim>, IDomainUser {

    public ApplicationIdentityUser()
        : base() {
        Images = new HashSet<Image>();
    }

    public string Name { get; set; }
    public virtual ICollection<Image> Images { get; set; }
}


public class ApplicationIdentityRole : IdentityRole<int, ApplicationIdentityUserRole>
{
    public ApplicationIdentityRole(){}

    public ApplicationIdentityRole(string name){Name = name;}
}

public class ApplicationIdentityUserRole : IdentityUserRole<int> {}

public class ApplicationIdentityUserClaim : IdentityUserClaim<int>{}

public class ApplicationIdentityUserLogin : IdentityUserLogin<int>{}

Также это мой конструктор моделей в методе OnModelCreating:

  modelBuilder.Entity<Image>()
            .Property(e => e.Id)
            .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        modelBuilder.Entity<Image>()
            .HasMany(e => e.Products)
            .WithRequired(e => e.Image)
            .WillCascadeOnDelete(false);
        modelBuilder.Entity<ApplicationIdentityUser>()
             .Property(e => e.Id)
             .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        modelBuilder.Entity<ApplicationIdentityRole>()
            .Property(e => e.Id)
            .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        modelBuilder.Entity<ApplicationIdentityUserClaim>()
             .Property(e => e.Id)
             .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

person Zaid Al-Omari    schedule 27.10.2014    source источник
comment
Таблицы AspNet * избыточны. От них нужно избавиться. Проверьте, что ваш ApplicationDbContext делает с этими таблицами?   -  person trailmax    schedule 27.10.2014
comment
мой ApplicationDbContext фактически движется из IdentityDbContext, и мне нужен способ хранения пользовательской информации. Вы имеете в виду, что я могу использовать таблицы, которые начинаются с Application *?   -  person Zaid Al-Omari    schedule 27.10.2014
comment
Я говорю, что должен быть только один набор таблиц * Users, * UserClaims и т. Д. Похоже, что способ наследования в ApplicationDbContext нарушен, и вы не переопределяете Users, Roles и другие, поэтому EF создает для вас 2 набора таблиц. Проверьте это.   -  person trailmax    schedule 27.10.2014
comment
хорошо, я обновлю свой вопрос, чтобы включить детали реализации   -  person Zaid Al-Omari    schedule 27.10.2014
comment
@trailmax, я обновил вопрос, проверьте ...   -  person Zaid Al-Omari    schedule 27.10.2014
comment
Как IDbsets выглядят в ApplicationDbContext?   -  person trailmax    schedule 27.10.2014
comment
в ApplicationDbContext нет IDbSet, сущности определяются только с использованием Fluent API в OnModelCreating (который также вызывает base.OnModelCreating). вы можете проверить полный проект на github по предоставленной ссылке (первая строка вопроса).   -  person Zaid Al-Omari    schedule 27.10.2014


Ответы (3)


Хорошо, я решил это, выполнив следующие действия:

  1. Включите в ядро ​​зависимость от Microsoft.AspNet.Identity.Core
  2. Реализуйте интерфейс IUser в AppUser (этот интерфейс поступает из Microsoft.AspNet.Identity.Core).
  3. Реализуйте интерфейс IRole для ApplicationRole.
  4. Полностью избавьтесь от IdentityDbContext и наследуйте только от DbContext.
  5. Внедрите собственную версию IUserStore *, указав своего AppUser
  6. Внедрите собственную версию IRoleStore, предоставив свою ApplicationRole.

Я знаю, что создание зависимости от Microsoft.AspNet.Identity.Core звучит странно, но нам нужен только интерфейс IUser, который в основном также считается базовой моделью домена для вашего приложения.

Конечная идея здесь состоит в том, чтобы полностью ИЗБАВИТЬСЯ от Microsoft.AspNet.Identity.EntityFramework.

Заинтересованные разработчики могут добавить +1, так что я могу загрузить полный рабочий образец на GitHub.

person Zaid Al-Omari    schedule 29.10.2014
comment
Я как раз собирался отправиться в это путешествие, когда пришел к такому же выводу, что Microsoft.AspNet.Identity.EntityFramework - хороший пример кода, но мешает вашему домену, если вы хотите, чтобы пользователи были первоклассными моделями предметной области. - person Chris Gomez; 06.12.2014
comment
Хотелось бы увидеть, как вы избавились от IdentityDbContext и как вы указали свой ApplicationIdentityUser в объекте Image, поскольку он находится в ядре, а не на уровне данных! Любой пример будет оценен по достоинству. - person webStuff; 29.05.2015
comment
Есть ли шанс разместить пример на GitHub? - person webStuff; 23.06.2015
comment
собирались выставить образец? - person Brian Rice; 16.08.2015
comment
Думаю, это образец github.com/imranbaloch/ASPNETIdentityWithOnion - person Ruchan; 11.05.2016
comment
Я так не думаю, поищите в репозитории и вы найдете Microsoft.AspNet.Identity.EntityFramework. - person JoshYates1980; 24.02.2017

Я использую эту структуру, нет необходимости иметь ссылку в каждой сущности. Чтобы получить ссылку на идентификатор пользователя, я добавил свойство UserIDBy в BaseEntity, чтобы каждая сущность унаследовала его.

public abstract class BaseEntity
{
    public int Id { get; set; }
    public string UserIDBy { get; set; }
}

Затем в веб-проекте уже есть метод расширения с именем GetUserId(this IIdentity identity) в IdentityExtensions.cs, поэтому для хранения UserIDBy в каждом результате действия Create и Edit:

Результат создания действия:

 // POST: /Region/Create
    [HttpPost]
    public async Task<ActionResult> Create([Bind(Include = "RegionName")] Region region)
    {
        if (ModelState.IsValid)
        {
            // TODO: Add insert logic here
            var id = User.Identity.GetUserId();
            region.UserIDBy = id.ToString(); 

            await _regionService.AddAsync(region);
            return Json(new { success = true });
        }

        return PartialView("_Create", region);
    }

Изменить результат действия:

 //// POST: /Region/Edit/5
    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Edit([Bind(Include = "id,RegionName")] Region region)
    {
        if (ModelState.IsValid)
        {
            var id = User.Identity.GetUserId();
            region.UserIDBy = id.ToString(); 
            _regionService.Update(region);
            return Json(new { success = true });
        }
        return PartialView("_Edit", region);
    }

Не забудьте импортировать:

using Myapp.Web.Extensions;
person Marouane Afroukh    schedule 03.12.2015
comment
Очень умно. Спасибо, что поделился. ASPNETIdentityWithOnion - отличная оболочка, но головная боль, связанная с созданием связи с настраиваемыми таблицами и платформой идентификации, того не стоит. - person JoshYates1980; 24.02.2017
comment
У вас есть проект с открытым исходным кодом, который реализует ASPNETIdentityWithOnion? - person JoshYates1980; 24.02.2017

Просто наткнулся на это, имея такую ​​же проблему.

Проблема с отмеченным ответом заключается в том, что он по-прежнему ссылается на Microsoft.AspNet, что затрудняет будущие планы .NET Core.

Основная проблема на самом деле связана с общей попыткой встроить функцию аутентификации в ядро, что противоречит цели.

Подумайте о том, чтобы встроенные функции для веб-аутентификации и авторизации оставались на веб-уровне и ссылались на основной объект пользователя (UserProfile?), Который представляет потребности Core. Это также упростило бы переход на другой метод аутентификации (AD).

В зависимости от ваших предпочтений вы можете затем ссылаться на Core.UserProfile из вашего AspNetUser, чтобы избежать множественных SQL-вызовов, или просто убедитесь, что у вас есть хорошая политика кеширования для операций Core.UserProfile.

Это позволяет вам управлять методами аутентификации отдельно от вашей базовой модели.

person Classe    schedule 19.07.2017