Использование удостоверения 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 в качестве резервной БД.