Нет службы для типа Identity.UserManager при использовании нескольких пользователей удостоверений
Моя настройка
В настоящее время у меня есть две модели, которые наследуются от ApplicationUser
, который наследует IdentityUser
. Пользовательские классы:
public abstract class ApplicationUser : IdentityUser
{
[PersonalData]
public string FirstName { get; set; }
[PersonalData]
public string LastName { get; set; }
[NotMapped]
public string FullName => $"{FirstName} {LastName}";
}
public class StudentUser : ApplicationUser
{
[PersonalData]
[Required]
public string StudentNumber { get; set; }
// A user belongs to one group
public Group Group { get; set; }
}
public class EmployeeUser : ApplicationUser { }
ApplicationUser
содержит общие свойства, такие как имя и фамилия. И StudentUser
и EmployeeUser
имеют свои собственные свойства и отношения. Эта структура следует наследованию таблицы на иерархию (TPH).
В идеале я хочу следовать наследованию таблиц по типу (TPT), потому что структура SQL лучше. ASP.NET Core изначально поддерживает только TPH, поэтому я использую подход TPT.
Эта проблема
Я добавил службу идентификации в Startup.cs
:
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
Когда я вызываю UserManager<StudentUser>
или UserManager<EmployeeUser>
, я получаю следующую ошибку:
Служба для типа "Microsoft.AspNetCore.Identity.UserManager'1 [ClassroomMonitor.Models.StudentUser]" не зарегистрирована.
Мой вопрос
К сожалению, я не могу найти много об этой ошибке в сочетании с этой реализацией.
Возможно ли (даже) заставить это работать таким образом?
Любая помощь или мысли приветствуются.
Обновление 1
StudentUser
добавление StudentUser
или EmployeeUser
в качестве сервисов с определенной областью не работает (упоминается в качестве первого ответа).
services.AddScoped<UserManager<ApplicationUser>, UserManager<ApplicationUser>>();
// or..
services.AddScoped<UserManager<ApplicationUser>>();
Это приводит к следующей ошибке:
InvalidOperationException: невозможно разрешить службу для типа 'Microsoft.AspNetCore.Identity.IUserStore1 [ClassroomMonitor.Models.StudentUser]'
Обновление 2
Вот Гист, чтобы дать вам лучшее представление о структуре проекта:
Ответы
Ответ 1
В идеале вы бы назвали одну и ту же настройку идентификации для производных типов пользователей, как и для базового типа пользователя.
К сожалению, метод AddIdentity
содержит код, который предотвращает его использование более одного раза.
Вместо этого вы можете использовать AddIdentityCore
. Службы роли уже зарегистрированы с помощью AddIdentity
, единственное отличие состоит в том, что AddIdentityCore
регистрирует UserClaimsPrincipalFactory<TUser>
, поэтому для соответствия настройке AddIdentity
его необходимо заменить на UserClaimsPrincipalFactory<TUser, TRole>
через метод AddClaimsPrincipalFactory
.
Код выглядит примерно так:
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders()
.AddDefaultUI();
services.AddIdentityCore<StudentUser>()
.AddRoles<IdentityRole>()
.AddClaimsPrincipalFactory<UserClaimsPrincipalFactory<StudentUser, IdentityRole>>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders()
.AddDefaultUI();
services.AddIdentityCore<EmployeeUser>()
.AddRoles<IdentityRole>()
.AddClaimsPrincipalFactory<UserClaimsPrincipalFactory<EmployeeUser, IdentityRole>>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders()
.AddDefaultUI();
Конечно, вы можете перемещать общие части в пользовательских методах расширения.
Обновление. Хотя службы роли уже настроены, вам все равно нужно вызвать AddRoles
, чтобы правильно установить свойство Role
для IndentityBuilder
, которое затем используется в AddEntityFrameworkStores
.
Ответ 2
Вам не хватает регистра DI для этого.
services.AddScoped<UserManager<AppUser>, UserManager<AppUser>>()
StudentUser и EmployeeUser похожи на него
Ответ 3
Протестировано по новому проекту:
dotnet new mvc --auth Индивидуальный
Startup.cshtml
services.AddDefaultIdentity<User>()
.AddEntityFrameworkStores<ApplicationDbContext>();
User.cs
public class User : IdentityUser
{
public string Test { get; set; }
}
Наверное, здесь ваша проблема:
_LoginPartial.cshtml
@inject SignInManager<User> SignInManager
@inject UserManager<User> UserManager
Также протестирован таким образом:
Startup.cs
services.AddDefaultIdentity<User2>()
.AddEntityFrameworkStores<ApplicationDbContext>();
Users.cs
public class User : IdentityUser
{
public string TestA { get; set; }
}
public class User2 : User
{
public string TestB { get; set; }
}
_LoginPartial.cshtml
@inject SignInManager<User2> SignInManager
@inject UserManager<User2> UserManager
Ответ 4
Вы не можете добавлять области для разных типов пользователей, у вас должно быть не так много разных типов, которые производны от IdentityUser, так как это будет означать, что вы будете либо иметь неправильные типы, используемые по всему месту, либо несколько разных пользовательских таблиц в базе данных.
вы должны структурировать свои данные таким образом, чтобы у него был ApplicationUser
который ссылается объект-сотрудник (отдельный объект) или объект-студент (опять-таки отдельный объект). здесь больше проблемы с дизайном, чем проблема с кодом.
ASPIdentity будет вводить Usermanager<ApplicationUser>
когда вы AddIdentity<ApplicationUser, IdentityRole>
, поэтому добавление большего количества менеджеров пользователей не будет работать AddIdentity<ApplicationUser, IdentityRole>
образом.
Ответ: вы должны создавать разные сущности для каждого типа пользователей, 1 для студентов, 1 для сотрудников и т.д., Все они будут иметь внешний ключ для идентификатора пользователя, и это позволит вам добавлять несколько типов пользователей без необходимости разные таблицы для каждого типа пользователя.
то когда вы addIdentity
вы можете зарегистрировать ApplicationUser
(как сейчас), а затем ввести UserManager<ApplicationUser>
который получит тип пользователя.