Использование удостоверения ASP.NET в приложении ASP.NET Core MVC без Entity Framework и миграций

Можно ли использовать ASP.NET Identity без миграции Entity Framework и Entity Framework? Остальная часть моего приложения будет использовать Micro ORM для доступа к данным. Тем не менее, приложение использует встроенные учетные записи отдельных пользователей ASP.NET Identity.

Моя цель состоит в том, чтобы по-прежнему иметь возможность использовать встроенные классы UserManager и LoginManager, дополнительно получать список пользователей с помощью Micro ORM и покончить с чем-либо, связанным с EF/Migrations. Это возможно? Не похоже, что это так, поскольку исходная структура базы данных создается путем применения начальной миграции.

Если у кого-то есть хорошая техника для этого, пожалуйста, поделитесь.

2 ответа

Решение

Сначала вам нужно создать пользовательский магазин:

public class UserStore : IUserStore<IdentityUser>,
                         IUserClaimStore<IdentityUser>,
                         IUserLoginStore<IdentityUser>,
                         IUserRoleStore<IdentityUser>,
                         IUserPasswordStore<IdentityUser>,
                         IUserSecurityStampStore<IdentityUser>
{
    // interface implementations not shown
}

Затем вам нужно зарегистрировать его в контейнере внедрения зависимостей:

// Add identity types
services.AddIdentity<ApplicationUser, ApplicationRole>()
    .AddDefaultTokenProviders();

// Identity Services
services.AddTransient<IUserStore<ApplicationUser>, CustomUserStore>();
services.AddTransient<IRoleStore<ApplicationRole>, CustomRoleStore>();

Это задокументировано здесь.

Asp.Net Identity вычеркнула необходимые магазины, а документация по ним находится здесь;
https://docs.microsoft.com/en-us/aspnet/core/security/authentication/identity-custom-storage-providers

Это пример магазина;

public class InMemoryUserStore<TUser> :
        IUserStore<TUser>,
        IUserLoginStore<TUser>,
        IUserClaimStore<TUser>,
        IUserPasswordStore<TUser>,
        IUserSecurityStampStore<TUser>,
        IUserTwoFactorStore<TUser>,
        IUserEmailStore<TUser>,
        IUserLockoutStore<TUser>,
        IUserAuthenticatorKeyStore<TUser>,
        IUserTwoFactorRecoveryCodeStore<TUser>,
        IUserPhoneNumberStore<TUser> where TUser: MemoryIdentityUser
    {
        ...
    }

Вы также можете иметь свой собственный объект User, и он не должен наследоваться ни от чего.

public class MemoryIdentityUser
{
    private List<MemoryUserClaim> _claims;
    private List<MemoryUserLogin> _logins;
    private List<MemoryUserToken> _tokens;
    ...
}

Asp.Net Идентичность является двигателем и, как таковая, является самоуверенным. Именно это мнение привело к абстракции магазинов. Мне бы хотелось, чтобы в документации Asp.Net Identity были приведены полные диаграммы последовательности действий для взаимодействия с магазинами. Как минимум несколько эталонных последовательностей, которые должны соблюдаться.

Хранилище имеет некоторые причуды, когда ему требуются методы, которые предназначены только для изменения личных данных в реализации, а затем последуют вызовы обновления, которые предполагают, что вы передадите эти данные в постоянное хранилище.

Возможно, вы захотите проверить этот проект; https://github.com/ghstahl/AspNetCore.2.InMemoryIdentity

Вы можете увидеть, что вам нужно сделать, не обременяя себя базой данных.

Подключить его;

// My user is custom, so I made ApplicationUser inherit
public class ApplicationUser : MemoryIdentityUser
{
}

Startup.cs;

public void ConfigureServices(IServiceCollection services)
{
  services.AddSingleton<IUserStore<ApplicationUser>>(provider =>
  {
    return new InMemoryUserStore<ApplicationUser>();
  });
  services.AddIdentity<ApplicationUser>(Configuration)
          .AddDefaultTokenProviders();

  // Add application services.
  services.AddTransient<IEmailSender, EmailSender>();

  services.AddMvc();
}

В AddIdentity нижеследующее иллюстрирует, насколько вы можете внести свои собственные реализации

public static class InMemoryIdentityServiceCollectionExtensions
{
    public static IdentityBuilder AddIdentity<TUser>(this IServiceCollection services, IConfiguration configuration)
        where TUser : class => services.AddIdentity<TUser>(configuration,null);

    public static IdentityBuilder AddIdentity<TUser>(this IServiceCollection services, IConfiguration configuration,Action<IdentityOptions> setupAction)
        where TUser : class
    {
        // Services used by identity
        var authenticationBuilder = services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = IdentityConstants.ApplicationScheme;
                options.DefaultChallengeScheme = IdentityConstants.ApplicationScheme;
                options.DefaultSignInScheme = IdentityConstants.ExternalScheme;
            })
            .AddCookie(IdentityConstants.ApplicationScheme, o =>
            {
                o.LoginPath = new PathString("/Account/Login");
                o.Events = new CookieAuthenticationEvents
                {
                    OnValidatePrincipal = SecurityStampValidator.ValidatePrincipalAsync
                };
            })
            .AddCookie(IdentityConstants.ExternalScheme, o =>
            {
                o.Cookie.Name = IdentityConstants.ExternalScheme;
                o.ExpireTimeSpan = TimeSpan.FromMinutes(5);
            })
            .AddCookie(IdentityConstants.TwoFactorRememberMeScheme,
                o => o.Cookie.Name = IdentityConstants.TwoFactorRememberMeScheme)
            .AddCookie(IdentityConstants.TwoFactorUserIdScheme, o =>
            {
                o.Cookie.Name = IdentityConstants.TwoFactorUserIdScheme;
                o.ExpireTimeSpan = TimeSpan.FromMinutes(5);
            });

        // Hosting doesn't add IHttpContextAccessor by default
        services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();

        // Identity services
        services.TryAddScoped<IUserValidator<TUser>, UserValidator<TUser>>();
        services.TryAddScoped<IPasswordValidator<TUser>, PasswordValidator<TUser>>();
        services.TryAddScoped<IPasswordHasher<TUser>, PasswordHasher<TUser>>();
        services.TryAddScoped<ILookupNormalizer, UpperInvariantLookupNormalizer>();

        // No interface for the error describer so we can add errors without rev'ing the interface
        services.TryAddScoped<IdentityErrorDescriber>();
        services.TryAddScoped<ISecurityStampValidator, SecurityStampValidator<TUser>>();
        services.TryAddScoped<IUserClaimsPrincipalFactory<TUser>, UserClaimsPrincipalFactory<TUser>>();
        services.TryAddScoped<UserManager<TUser>, AspNetUserManager<TUser>>();
        services.TryAddScoped<SignInManager<TUser>, SignInManager<TUser>>();

        if (setupAction != null)
        {
            services.Configure(setupAction);
        }

        return new IdentityBuilder(typeof(TUser), services);
    }
}

Существует множество реализаций IUserStore с каждым типом резервной базы данных. Я скопировал свой InMemoryUserStore из другого проекта, который использовал MongoDB в качестве резервной БД.

Другие вопросы по тегам