Идентификация ASP NET Core с настраиваемым DbContext Entity Framework

Я пробовал читать документы по ASP.NET Core Identity и Entity Framework. Но я все еще не чувствую себя мудрее.

Я не хочу иметь ничего общего с IdentityDbContext, IdentityUser, IdentityRole. Я просто хочу использовать свою собственную реализацию DbContext и успешно работать с UserManager, UserStore, RoleManager, SignInManager и другими классами, участвующими в входе в систему.

Итак, как было сказано, мы создали проект ASP.NET Core по умолчанию, который использует «Индивидуальные учетные записи пользователей». Теперь я хочу выяснить, какой провод DI требуется для того, чтобы этот контроллер «работал».

Смотрим на конструктор контроллера учетной записи:

public AccountController(UserManager<ApplicationUser> userManager,
        SignInManager<ApplicationUser> signInManager,
        IOptions<IdentityCookieOptions> identityCookieOptions,
        IEmailSender emailSender,
        ISmsSender smsSender,
        ILoggerFactory loggerFactory)

Наряду с этим генерируются следующие связанные классы:

public class ApplicationUser : IdentityUser
{
}

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    ...
}

И некоторая связанная конфигурация DI:

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

    services.AddIdentity<ApplicationUser, IdentityRole>()
        .AddEntityFrameworkStores<ApplicationDbContext>()
        .AddDefaultTokenProviders();
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    ...
    app.UseIdentity();
}

Копаясь в исходном коде ASP.NET Core Identity, UserStore накладывает ограничение на IdentityUser.

public class UserStore : UserStore<IdentityUser<string>>

Я хочу работать примерно со следующим - для начала:

public class AuthenticationDbContext : DbContext
{
    public AuthenticationDbContext(DbContextOptions options) : base(options)
    {
    }

    public DbSet<ApplicationUser> ApplicationUsers { get; set; }
    public DbSet<ApplicationRole> ApplicationRoles { get; set; }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);

        builder.Entity<ApplicationUser>(te =>
          te.HasKey(user => user.Id));

        builder.Entity<ApplicationRole>(te =>
          te.HasKey(role => role.Id));
     }
}

public class ApplicationRole
{
    public int Id { get; set; }
    public string UserName { get; set; }
}

public class ApplicationUser
{
    public int Id { get; set; }
    public Guid Guid { get; set; }
    public string GivenName { get; set; }
    public string FamilyName { get; set; }
    public string MiddleName { get; set; }
    public DateTime? DateOfBirth { get; set; }
    public string UserName { get; set; }
    public string EmailAddress { get; set; }
}

Если бы я перечислил проблемы, которые у меня были, исключения и др., Этот пост был бы слишком длинным.

Вопрос в том, как мне подключить это к конфигурации DI?


person Andez    schedule 28.03.2017    source источник
comment
Хорошо, теперь у меня что-то работает, поэтому теперь вызывается конструктор AccountController и вводятся зависимости. Это связано с реализацией настраиваемых ApplicationUserStore и ApplicationRoleStore. Опубликую решение, как только я это выясню.   -  person Andez    schedule 29.03.2017
comment
Он уже был подключен ... в методе ConfigureServices ...   -  person mvermef    schedule 29.03.2017
comment
Вышеуказанное не работает. Я сознательно не вставлял ошибок, поскольку я возвращался и назад, пробуя реализации каждого класса - добавляя различные комбинации в DI services.AddIdentity (...). AddXXX. Я перефразирую вопрос позже, когда вернусь домой.   -  person Andez    schedule 29.03.2017
comment
Почему вы не хотите наследовать от IdentityUser и т. Д.? Вот как это должно быть использовано, зачем отклоняться от этого? Гораздо проще сделать это правильно.   -  person Sami Kuhmonen    schedule 29.03.2017
comment
Может быть, но у меня просто неприятное ощущение, что это не чистое наследование IdentityUser, поэтому я бы поставил под сомнение правильность этого способа. Учитывая, что UserStore накладывает ограничение на IdentityUser, IUserStore нет. Я чувствую, что могу последовать примеру Лискова в этом вопросе и предоставить свою собственную реализацию любой из реализаций. Я скоро поставлю свой ответ - возможно, это не технически правильно, но это начало пути.   -  person Andez    schedule 30.03.2017


Ответы (1)


OK. Следуя тому, чтобы мой AuthenticationDbContext оставался неизменным, я могу предоставить реализацию IUserStore, IRoleStore и настроить DI следующим образом.

public class ApplicationUserStore : IUserStore<ApplicationUser>, IUserPasswordStore<ApplicationUser>
{
    private readonly AuthenticationDbContext _dbContext;

    public ApplicationUserStore(AuthenticationDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    ...

Хорошо, поэтому мне нужно предоставить здесь реализации 10 или 11 методов, которые нужно немного разобраться. То же самое и для ApplicationRoleStore.

public class ApplicationRoleStore : IRoleStore<ApplicationRole>
{
    private AuthenticationDbContext _dbContext;

    public ApplicationRoleStore(AuthenticationDbContext context, IdentityErrorDescriber describer = null) 
    {
        _dbContext = context;
    }

    ...

Затем это можно подключить с помощью:

public void ConfigureServices(IServiceCollection services)
{
    services.AddIdentity<ApplicationUser, ApplicationRole>()
        .AddUserStore<ApplicationUserStore>()
        .AddRoleStore<ApplicationRoleStore>()
        .AddDefaultTokenProviders();

     services.AddTransient(c =>
            new AuthenticationDbContext(
                new DbContextOptionsBuilder()
                    .UseSqlServer(Configuration.GetConnectionString("DefaultConnection")).Options));

Таким образом, вход в систему через Account Controller / Login теперь вызывает мой ApplicationUserStore.FindByNameAsync, когда я нажимаю на Login.

Еще неизвестно, является ли это «правильным» или нет. Я просто твердо уверен, что ASP.NET Identity должен работать с «любой» реализацией хранилища данных, поэтому вы не должны ограничиваться использованием IdentityUser. Вышесказанное должно работать для реализаций, отличных от Entity Framework, как мне кажется.

person Andez    schedule 30.03.2017