C# ASP.NET MVC框架中使用Identity Core的标识
我在部分切换到.NET标准时遇到问题 我正在将类库迁移到.NET标准的过程中,在这个库中我有存储库和数据库通信。我已经成功地将其迁移到使用C# ASP.NET MVC框架中使用Identity Core的标识,c#,asp.net-mvc,asp.net-core,asp.net-identity,.net-standard,C#,Asp.net Mvc,Asp.net Core,Asp.net Identity,.net Standard,我在部分切换到.NET标准时遇到问题 我正在将类库迁移到.NET标准的过程中,在这个库中我有存储库和数据库通信。我已经成功地将其迁移到使用AspNetCore.Identity.EntityFrameworkCore。我试图实现的是最终有1个.NET标准项目负责数据库,其中1个MVC.NET Framework、1个API.NET Framework和1个新的.NET核心应用程序将使用它。除此之外,其他一些.NETFramework类库也依赖于它。基本上,.NET核心应用程序已经制作完成,但后端
AspNetCore.Identity.EntityFrameworkCore
。我试图实现的是最终有1个.NET标准项目负责数据库,其中1个MVC.NET Framework、1个API.NET Framework和1个新的.NET核心应用程序将使用它。除此之外,其他一些.NETFramework类库也依赖于它。基本上,.NET核心应用程序已经制作完成,但后端没有因为功能重叠而“合并”
小概览:
不将MVC/API转换为.Core的原因是,目前有太多其他库依赖于.NET Framework,有些库尚未转换,但对数据库使用相同的库是一个根本性的更改,这将避免某些存储库的双重实现
我还已经转换了实现Microsoft.AspNetCore.Identity.IdentityUser
,Microsoft.AspNetCore.Identity.IdentityRole
等的实体。
因此,我的DbContext类如下所示:
public class DatabaseContext : IdentityDbContext<ApplicationUser, ApplicationRole, string, ApplicationUserClaim, ApplicationUserRole, ApplicationUserLogin, ApplicationRoleClaim, ApplicationUserToken>
{
private IConfiguration _config;
public DatabaseContext(IConfiguration config) : base()
{
_config = config;
}
//all DbSet, OnModelCreating
}
嗯,我想这并没有多大用处,而且我在两个.NET Framework项目中都使用SimpleInjector,如果可能的话,我更愿意继续使用SimpleInjector,而不是使用默认的依赖项注入器
通过添加上面的内容,我真的不知道如何使用ConfigureAuth
方法以及将所有配置放在哪里
当我尝试调整IdentityManager时,尝试在AspNetCore.Identity
中引用相同的类型,在尝试更改ApplicationUserManager
时,我开始遇到问题:
创建UserStore不是问题,但是尝试创建UserManager
更困难,我也尝试在我的UserRepository
中使用它,就像我以前做的那样,现在我不能再使用它了:(
旧用户存储库
private readonly UserManager<ApplicationUser, string> _userManager = null;
private readonly RoleManager<ApplicationRole, string> _roleManager = null;
internal static IDataProtectionProvider DataProtectionProvider { get; private set; }
public UserRepository(DatabaseContext dbContext) : base(dbContext, c => c.contactId, m => m.ContactId)
{
var userStore =
new UserStore<ApplicationUser, ApplicationRole, string, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>(dbContext);
var roleStore = new RoleStore<ApplicationRole, string, ApplicationUserRole>(dbContext);
_userManager = new UserManager<ApplicationUser, string>(userStore);
_roleManager = new RoleManager<ApplicationRole, string>(roleStore);
_userManager.UserValidator = new UserValidator<ApplicationUser>(_userManager) { AllowOnlyAlphanumericUserNames = false };
if (DataProtectionProvider == null)
{
DataProtectionProvider = new MachineKeyProtectionProvider();
}
_userManager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser, string>(DataProtectionProvider.Create("Identity"));
}
private readonly UserManager将它们放到那里当然我首先要解决根本问题
最后但并非最不重要的一点:请记住,这些应用程序都已投入生产,因此,特别是在用户周围,我需要确保所有登录都正常工作。当此版本上线时,由于其他一些迁移问题,我需要将数据迁移到新数据库。好的,这是一个很长的答案,请做好准备o第二天花在把你的头发从你头上拔下来:)
首先是由两个不同类实现的iaapplicationuser
接口:
public interface IApplicationUser
{
string Id { get; set; }
/// <summary>Gets or sets the user name for this user.</summary>
string UserName { get; set; }
}
.NET Framework的实施:
public class IdentityManagerMvc : IIdentityManager
{
private readonly UserManager<ApplicationUserMvc, string> _userManager = null;
private readonly RoleManager<ApplicationRoleMvc, string> _roleManager = null;
internal static IDataProtectionProvider DataProtectionProvider { get; private set; }
public IdentityManagerMvc(DatabaseContextMvc dbContext)
{
var userStore =
new UserStore<ApplicationUserMvc, ApplicationRoleMvc, string, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>(dbContext);
var roleStore = new RoleStore<ApplicationRoleMvc, string, ApplicationUserRole>(dbContext);
_userManager = new UserManager<ApplicationUserMvc, string>(userStore);
_roleManager = new RoleManager<ApplicationRoleMvc, string>(roleStore);
_userManager.UserValidator = new UserValidator<ApplicationUserMvc>(_userManager) { AllowOnlyAlphanumericUserNames = false };
if (DataProtectionProvider == null)
{
DataProtectionProvider = new MachineKeyProtectionProvider();
}
_userManager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUserMvc, string>(DataProtectionProvider.Create("Identity"));
}
public async Task<IIdentityResult> CreateAsync(IApplicationUser user)
{
ApplicationUserMvc realUser = new ApplicationUserMvc()
{
Id = user.Id,
TemporaryToken = user.TemporaryToken,
AccessFailedCount = user.AccessFailedCount,
ConcurrencyStamp = user.ConcurrencyStamp,
Email = user.Email,
EmailConfirmed = user.EmailConfirmed,
LockoutEnabled = user.LockoutEnabled,
LockoutEnd = user.LockoutEnd,
NormalizedEmail = user.NormalizedEmail,
NormalizedUserName = user.NormalizedUserName,
PasswordHash = user.PasswordHash,
PhoneNumber = user.PhoneNumber,
PhoneNumberConfirmed = user.PhoneNumberConfirmed,
RequiresPasswordCreation = user.RequiresPasswordCreation,
SecurityStamp = user.SecurityStamp,
TwoFactorEnabled = user.TwoFactorEnabled,
UserName = user.UserName
};
var result = await _userManager.CreateAsync(realUser);
return ConvertToInterface(result);
}
private IIdentityResult ConvertToInterface(IdentityResult result)
{
IIdentityResult realResult = new IdentityResultMvc();
realResult.Succeeded = result.Succeeded;
realResult.Errors = result.Errors?.ToList();
return realResult;
}
}
public class IdentityResultMvc : IdentityResult, IIdentityResult
{
private IEnumerable<string> _errors;
private bool _succeed;
public new bool Succeeded
{
get => base.Succeeded || _succeed;
set => _succeed = value;
}
public new List<string> Errors
{
get => base.Errors?.ToList() ?? _errors?.ToList();
set => _errors = value;
}
}
此时,您应该拥有在任何地方使用它所需的所有类。
例如,在.NET Framework项目中,您可以使用ApplicationUserManager
如下所示:
public class ApplicationUserManager : UserManager<ApplicationUserMvc, string>
{
public ApplicationUserManager(IUserStore<ApplicationUserMvc, string> store)
: base(store)
{//look at where i used applicationUserMvc
}
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
var userStore =
new UserStore<ApplicationUserMvc, ApplicationRoleMvc, string, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>(context.Get<DatabaseContextMvc>());
//ApplicationUserLogin,UserRole,UserClaim are self created but just override IdentityUserLogin (for example).
var manager = new ApplicationUserManager(userStore);
}
...
}
您的重点可能已经在这篇长文章之后或在实施之后消失了,但还有几句话:
- 我可以保证,有了这一点,你会使它工作,它的工作完美的过去半年
- 因此.NET标准(以及EntityFrameworkCore)是执行数据库操作的主要方式,大多数代码都是为了处理.NET Framework
- 您将努力安装正确的依赖项。它将导致运行时异常,您将很快遇到这些异常,但很容易解决,.NET Framework只需要为自己安装依赖项。确保版本对齐,使用Manage NuGet packages for Solution(右键单击Solution)下的Consolidate版本
- 您必须以netcore的方式进行设置:因此在.NET Framework项目中也需要appsettings.json。您还需要在Web.Config中使用它,这主要用于身份验证的一小部分
private IConfiguration GetConfiguartion()
{
var path = Server.MapPath("~/");
var builder = new ConfigurationBuilder()
.SetBasePath(path)
.AddJsonFile("appsettings.json");
return builder.Build();//inject the return IConfiguration in your DI
}
- 祝你好运。如果您认为这很困难并且会造成很多麻烦:正确,如果您有一个小型应用程序,那么最好将所有内容转换为.NET Core/.NET标准
我最终解决了这个问题,我会尽快更新答案,只是想知道你是怎么解决的?我有一个类似的场景,我们有一个提供管理系统的遗留应用程序,但我正在构建一个新的面向客户的.net core API,但需要在net core和net standard之间共享标识表,并且存在一些模式差异,即LockoutEndvs LockoutEndDateUtc。到目前为止,我的代码与上面的方法非常相似,但我还没有成功地使其正常工作yet@mcinnes01啊,看来我忘了在这里写答案了。今晚我会写这个。尽管很遗憾,我无法正确配置DataProtectionProvider,例如,重置密码只需在数据库用户表中存储一个令牌即可。我确实解决了在带有identity manager的.net core/framework和其他东西中使用1数据库上下文的问题。@mcinnes01我的答案已发布,希望您能理解。非常感谢,我将尝试一下:)
public interface IIdentityManager
{
//User manager methods
Task<IIdentityResult> CreateAsync(IApplicationUser user);
//..all methods needed
}
public interface IIdentityResult
{
bool Succeeded { get; set; }
List<string> Errors { get; set; }
}
public class IdentityManagerCore : IIdentityManager
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly RoleManager<ApplicationRole> _roleManager;
public IdentityManagerCore(UserManager<ApplicationUser> userManager, RoleManager<ApplicationRole> roleManager)
{
_userManager = userManager;
_roleManager = roleManager;
}
public async Task<IIdentityResult> CreateAsync(IApplicationUser user)
{
ApplicationUser realUser = new ApplicationUser()
{
Id = user.Id,
TemporaryToken = user.TemporaryToken,
AccessFailedCount = user.AccessFailedCount,
ConcurrencyStamp = user.ConcurrencyStamp,
Email = user.Email,
EmailConfirmed = user.EmailConfirmed,
LockoutEnabled = user.LockoutEnabled,
LockoutEnd = user.LockoutEnd,
NormalizedEmail = user.NormalizedEmail,
NormalizedUserName = user.NormalizedUserName,
PasswordHash = user.PasswordHash,
PhoneNumber = user.PhoneNumber,
PhoneNumberConfirmed = user.PhoneNumberConfirmed,
RequiresPasswordCreation = user.RequiresPasswordCreation,
SecurityStamp = user.SecurityStamp,
TwoFactorEnabled = user.TwoFactorEnabled,
UserName = user.UserName
};
var result = await _userManager.CreateAsync(realUser);
return ConvertToInterface(result);
}
private IIdentityResult ConvertToInterface(IdentityResult result)
{
IIdentityResult realResult = new IdentityResultCore();
realResult.Succeeded = result.Succeeded;
realResult.Errors = result.Errors?.Select(x => x.Description).ToList();
return realResult;
}
}
public class IdentityResultCore : IdentityResult, IIdentityResult
{
private IEnumerable<string> _errors;
private bool _succeed;
public new bool Succeeded
{
get => base.Succeeded || _succeed;
set => _succeed = value;
}
public new List<string> Errors
{
get => base.Errors?.Select(x => x.Description).ToList() ?? _errors?.ToList();
set => _errors = value;
}
}
services.AddTransient<IIdentityManager, IdentityManagerCore>();
public class IdentityManagerMvc : IIdentityManager
{
private readonly UserManager<ApplicationUserMvc, string> _userManager = null;
private readonly RoleManager<ApplicationRoleMvc, string> _roleManager = null;
internal static IDataProtectionProvider DataProtectionProvider { get; private set; }
public IdentityManagerMvc(DatabaseContextMvc dbContext)
{
var userStore =
new UserStore<ApplicationUserMvc, ApplicationRoleMvc, string, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>(dbContext);
var roleStore = new RoleStore<ApplicationRoleMvc, string, ApplicationUserRole>(dbContext);
_userManager = new UserManager<ApplicationUserMvc, string>(userStore);
_roleManager = new RoleManager<ApplicationRoleMvc, string>(roleStore);
_userManager.UserValidator = new UserValidator<ApplicationUserMvc>(_userManager) { AllowOnlyAlphanumericUserNames = false };
if (DataProtectionProvider == null)
{
DataProtectionProvider = new MachineKeyProtectionProvider();
}
_userManager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUserMvc, string>(DataProtectionProvider.Create("Identity"));
}
public async Task<IIdentityResult> CreateAsync(IApplicationUser user)
{
ApplicationUserMvc realUser = new ApplicationUserMvc()
{
Id = user.Id,
TemporaryToken = user.TemporaryToken,
AccessFailedCount = user.AccessFailedCount,
ConcurrencyStamp = user.ConcurrencyStamp,
Email = user.Email,
EmailConfirmed = user.EmailConfirmed,
LockoutEnabled = user.LockoutEnabled,
LockoutEnd = user.LockoutEnd,
NormalizedEmail = user.NormalizedEmail,
NormalizedUserName = user.NormalizedUserName,
PasswordHash = user.PasswordHash,
PhoneNumber = user.PhoneNumber,
PhoneNumberConfirmed = user.PhoneNumberConfirmed,
RequiresPasswordCreation = user.RequiresPasswordCreation,
SecurityStamp = user.SecurityStamp,
TwoFactorEnabled = user.TwoFactorEnabled,
UserName = user.UserName
};
var result = await _userManager.CreateAsync(realUser);
return ConvertToInterface(result);
}
private IIdentityResult ConvertToInterface(IdentityResult result)
{
IIdentityResult realResult = new IdentityResultMvc();
realResult.Succeeded = result.Succeeded;
realResult.Errors = result.Errors?.ToList();
return realResult;
}
}
public class IdentityResultMvc : IdentityResult, IIdentityResult
{
private IEnumerable<string> _errors;
private bool _succeed;
public new bool Succeeded
{
get => base.Succeeded || _succeed;
set => _succeed = value;
}
public new List<string> Errors
{
get => base.Errors?.ToList() ?? _errors?.ToList();
set => _errors = value;
}
}
public class DatabaseContextMvc : IdentityDbContext<ApplicationUserMvc, ApplicationRoleMvc, string, ApplicationUserLogin,
ApplicationUserRole, ApplicationUserClaim>
{
public DatabaseContextMvc() : base("DatabaseContext")
{
Configuration.LazyLoadingEnabled = false;
Configuration.ProxyCreationEnabled = false;
//Database.SetInitializer<DatabaseContextMvc>(null);
}
public void SetTimeout(int minutes)
{
this.Database.CommandTimeout = minutes * 60;
}
public static DatabaseContextMvc Create()
{
return new DatabaseContextMvc();
}
}
public class ApplicationUserManager : UserManager<ApplicationUserMvc, string>
{
public ApplicationUserManager(IUserStore<ApplicationUserMvc, string> store)
: base(store)
{//look at where i used applicationUserMvc
}
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
var userStore =
new UserStore<ApplicationUserMvc, ApplicationRoleMvc, string, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>(context.Get<DatabaseContextMvc>());
//ApplicationUserLogin,UserRole,UserClaim are self created but just override IdentityUserLogin (for example).
var manager = new ApplicationUserManager(userStore);
}
...
}
public class DatabaseContext : IdentityDbContext<ApplicationUser, ApplicationRole, string, ApplicationUserClaim, ApplicationUserRole, ApplicationUserLogin, ApplicationRoleClaim, ApplicationUserToken>
{
private IConfiguration _config;
public string ConnectionString { get; }
public DatabaseContext(IConfiguration config) : base()
{
_config = config;
var connectionString = config.GetConnectionString("DatabaseContext");
ConnectionString = connectionString;
}
public void SetTimeout(int minutes)
{
Database.SetCommandTimeout(minutes * 60);
}
public virtual DbSet<Address> Addresses { get; set; }
public static DatabaseContext Create(IConfiguration config)
{
return new DatabaseContext(config);
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
//setup code for the DbContextOptions
optionsBuilder
.UseSqlServer(ConnectionString,
providerOptions => providerOptions.CommandTimeout(60))
.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
base.OnConfiguring(optionsBuilder);
}
private IConfiguration GetConfiguartion()
{
var path = Server.MapPath("~/");
var builder = new ConfigurationBuilder()
.SetBasePath(path)
.AddJsonFile("appsettings.json");
return builder.Build();//inject the return IConfiguration in your DI
}