使用Identity Core的ASP.NET MVC框架中的身份 [英] Identity in ASP.NET MVC Framework using Identity Core

查看:211
本文介绍了使用Identity Core的ASP.NET MVC框架中的身份的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我无法部分切换到.NET Standard。



我正在将类库迁移到.NET Standard,在该库中存储库和数据库通信。我已经成功地将此迁移为使用 AspNetCore.Identity.EntityFrameworkCore 。我试图实现的目标是最终拥有1个.NET Standard项目来管理数据库,其中将使用1个MVC .NET Framework,1个API .NET Framework和1个新的.NET Core应用程序。除此之外,其他一些.NET Framework类库也依赖于此。基本上已经制作了.NET Core应用程序,但尚未针对后端的功能进行合并。



小概述:





未将MVC / API转换为.Core的原因是,目前有太多其他库依赖于.NET Framework,有些尚不能转换,但是使用相同的库数据库是一项根本性的更改,它将避免某些存储库的双重实现。



我也已经转换了实现 Microsoft.AspNetCore.Identity的实体。 IdentityUser Microsoft.AspNetCore.Identity.IdentityRole 等。
所以我的DbContext类看起来像这样:

 公共类DatabaseContext:IdentityDbContext< ApplicationUser,ApplicationRole,字符串,ApplicationUserClaim,ApplicationUserRole,ApplicationUserLogin,ApplicationRoleClaim,ApplicationUserToken> 
{
private IConfiguration _config;
public DatabaseContext(IConfiguration config):base()
{
_config = config;
}
//所有DbSet,OnModelCreating
}

I已经成功运行了EFCore代码首次迁移。



现在,我正在尝试在MVC应用程序(以及API项目)中配置身份。

>

我只有标准的 IdentityConfig.cs Startup.Auth.cs 完成所有配置。我尝试查看此文档



创建UserStore没问题,但是尝试创建 UserManager 比较困难,我也尝试在 UserR中使用它储存库,就像我以前做过的那样,现在不再使用了:(。



旧的UserRepository

 私有只读UserManager< ApplicationUser,字符串> _userManager = null; 
私有只读RoleManager< ApplicationRole,字符串> _roleManager = null;

内部静态IDataProtectionProvider DataProtectionProvider {get;私人套装; }
public UserRepository(DatabaseContext dbContext):base(dbContext,c => c.contactId,m => m.ContactId)
{
var userStore =
new UserStore< ; ApplicationUser,ApplicationRole,字符串,ApplicationUserLogin,ApplicationUserRole,ApplicationUserClaim>(dbContext);
var roleStore = new RoleStore< ApplicationRole,string,ApplicationUserRole>(dbContext);
_userManager = new UserManager< ApplicationUser,string>(userStore);
_roleManager =新的RoleManager< ApplicationRole,string>(roleStore);
_userManager.UserValidator =新的UserValidator< ApplicationUser>(_ userManager){AllowOnlyAlphanumericUserNames = false};
if(DataProtectionProvider == null)
{
DataProtectionProvider = new MachineKeyProtectionProvider();
}
_userManager.UserTokenProvider = new DataProtectorTokenProvider< ApplicationUser,string>(DataProtectionProvider.Create( Identity));
}

尝试再次执行上述操作会在创建时出现问题UserManager 因为要询问9个参数,所以我有点觉得不应该这样做...可能要做类似的东西要使它们到达那里,我当然首先要解决根本问题。



最后但并非最不重要的一点:请记住,这些应用程序已经全部投入生产,因此特别是在用户周围,我需要确保所有登录名仍然有效。启用此版本后,由于其他一些迁移问题,我将需要将数据迁移到新数据库。

解决方案

这是一个很长的答案,请准备好第二天花时间将头发拔出头来:)。



首先是 IApplicationUser的接口由2个不同的类实现:

 公共接口IApplicationUser 
{
字符串ID {组; }

///< summary>获取或设置该用户的用户名。< / summary>
字符串UserName {get;组; }
}

实现1,这是我的数据库实体的一部分:

 公共类ApplicationUser:IdentityUser< string> ;, IApplicationUser 
{
public DateTime? LockoutEndDateUtc {get;组; }
public bool RequiresPasswordCreation {get;组; }
公共字符串TemporaryToken {get;组; }
}

.NET Framework项目的实施2:

 公共类ApplicationUserMvc:IdentityUser< string,ApplicationUserLogin,ApplicationUserRole,ApplicationUserClaim> ;, IApplicationUser 
{
public async Task< ClaimsIdentity> GenerateUserIdentityAsync(UserManager< ApplicationUserMvc,string>管理器)
{
//请注意,authenticationType必须与CookieAuthenticationOptions.AuthenticationType
中定义的身份匹配var userIdentity = await manager.CreateIdentityAsync(this,DefaultAuthenticationTypes.ApplicationCookie );
//在此处添加自定义用户声明

return userIdentity;
}
...所有其他事物
}

然后,我创建了自己的Identity Manager(接口)

 公共接口IIdentityManager 
{
//用户管理器方法
Task< IIdentityResult> ;; CreateAsync(IApplicationUser用户);
// ..需要的所有方法
}

公共接口IIdentityResult
{
bool成功{组; }
List< string>错误{组; }
}

然后我的实际实现,因此这是我的.NET

 公共类IdentityManagerCore:IIdentityManager 
{
private readonly UserManager< ApplicationUser> _userManager;
私有只读RoleManager< ApplicationRole> _roleManager;

public IdentityManagerCore(UserManager< ApplicationUser> userManager,RoleManager< ApplicationRole> roleManager)
{
_userManager = userManager;
_roleManager = roleManager;
}

公共异步任务< IIdentityResult> CreateAsync(IApplicationUser用户)
{
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);
}

私有IIdentityResult ConvertToInterface(IdentityResult result)
{
IIdentityResult realResult = new IdentityResultCore();
realResult.Succeeded = result.Succeeded;
realResult.Errors = result.Errors?.Select(x => xDescription).ToList();
返回realResult;
}
}

公共类IdentityResultCore:IdentityResult,IIdentityResult
{
private IEnumerable< string> _错误;
私人布尔值成功;
公共新布尔成功
{
get =>成功|| _成功;
set => _成功=值;
}

public new List< string>错误
{
get => base.Errors?.Select(x => x.Description).ToList()?? _errors?.ToList();
set => _errors =值;
}
}

UserManager RoleManager 像这样在启动时注入:

  services.AddTransient< IIdentityManager,IdentityManagerCore>(); 

.NET Framework实现:

 公共类IdentityManagerMvc:IIdentityManager 
{
private readonly UserManager< ApplicationUserMvc,string> _userManager = null;
私有只读RoleManager< ApplicationRoleMvc,string> _roleManager = null;

内部静态IDataProtectionProvider DataProtectionProvider {get;私人套装; }
public IdentityManagerMvc(DatabaseContextMvc dbContext)
{
var userStore =
new UserStore< ApplicationUserMvc,ApplicationRoleMvc,字符串,ApplicationUserLogin,ApplicationUserRole,ApplicationUserClaim>(dbContext);
var roleStore = new RoleStore< ApplicationRoleMvc,string,ApplicationUserRole>(dbContext);
_userManager =新的UserManager< ApplicationUserMvc,字符串>(userStore);
_roleManager =新的RoleManager< ApplicationRoleMvc,字符串>(roleStore);
_userManager.UserValidator =新的UserValidator< ApplicationUserMvc>(_ userManager){AllowOnlyAlphanumericUserNames = false};
if(DataProtectionProvider == null)
{
DataProtectionProvider = new MachineKeyProtectionProvider();
}
_userManager.UserTokenProvider = new DataProtectorTokenProvider< ApplicationUserMvc,字符串>(DataProtectionProvider.Create( Identity)));
}

公共异步任务< IIdentityResult> CreateAsync(IApplicationUser用户)
{
ApplicationUserMvc realUser =新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.TwoFactorEnable d,
UserName = user.UserName
};
var result = await _userManager.CreateAsync(realUser);
return ConvertToInterface(result);
}

私有IIdentityResult ConvertToInterface(IdentityResult结果)
{
IIdentityResult realResult = new IdentityResultMvc();
realResult.Succeeded = result.Succeeded;
realResult.Errors = result.Errors?.ToList();
返回realResult;
}
}


公共类IdentityResultMvc:IdentityResult,IIdentityResult
{
private IEnumerable< string> _错误;
私人布尔值成功;
公共新布尔成功
{
get =>成功|| _成功;
set => _成功=值;
}

public new List< string>错误
{
get => base.Errors?.ToList()?? _errors?.ToList();
set => _errors =值;
}
}

最后但并非最不重要的是,您需要单独的 DatabaseContext 用于您的.NET Framework项目,该项目仅用于身份目的,因此不实际查询任何数据,仅用于身份验证,授权。

 公共类DatabaseContextMvc:IdentityDbContext< ApplicationUserMvc,ApplicationRoleMvc,字符串,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 =分钟* 60;
}

公共静态DatabaseContextMvc Create()
{
return new DatabaseContextMvc();
}
}

此刻,您应该拥有所有必要的课程来随处使用。
例如,在您的.NET Framework项目中,您可以像这样使用 ApplicationUserManager

 公共类ApplicationUserManager:UserManager< ApplicationUserMvc,string> 
{
public ApplicationUserManager(IUserStore< ApplicationUserMvc,string> store)
:base(store)
{//看看我在哪里使用了applicationUserMvc
}

公共静态ApplicationUserManager Create(IdentityFactoryOptions< ApplicationUserManager>选项,IOwinContext上下文)
{
var userStore =
new UserStore< ApplicationUserMvc,ApplicationRoleMvc,字符串,ApplicationUserLogin,ApplicationUserRole,ApplicationUserClaim> (context.Get< DatabaseContextMvc>());
// ApplicationUserLogin,UserRole,UserClaim是自创建的,但仅覆盖IdentityUserLogin(例如)。
var manager = new ApplicationUserManager(userStore);
}
...
}

在任何依赖注入中在.NET Framework中使用时,请确保同时注册 DatabaseContext DatabaseContextMvc



这是我的 DatabaseContext ,它位于.NET Standard库中并在.NET Core和.NET Framework中使用:

 公共类DatabaseContext:IdentityDbContext< ApplicationUser,ApplicationRole,字符串,ApplicationUserClaim,ApplicationUserRole,ApplicationUserLogin,ApplicationRoleClaim,ApplicationUserToken> 
{
private IConfiguration _config;
公共字符串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);
}

公共虚拟DbSet< Address>地址{get;组; }

公共静态DatabaseContext创建(IConfiguration配置)
{
返回新的DatabaseContext(config);
}

受保护的重写void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
// DbContextOptions
optionsBuilder
的安装代码。UseSqlServer(ConnectionString ,
providerOptions => providerOptions.CommandTimeout(60))
.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
base.OnConfiguring(optionsBuilder);
}

您的关注点可能在此较长的帖子或实施后就已经消失了,但是A再说几句话:




  • 我可以保证,使用此功能,它可以在上半年使用。

  • 因此,.NET Standard(以及EntityFrameworkCore)是进行数据库操作的主要方式,大多数代码用于应对.NET Framework。

  • 您将与之抗争安装正确的依赖项。这将导致运行时异常,您将很快遇到但很容易解决的.NET Framework仅需要为其自身安装依赖项。确保版本对齐,在Manage NuGet软件包下使用合并版本作为解决方案(右键单击解决方案)。

  • 您将必须执行-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(); //将返回IConfiguration注入您的DI
    }


  • 祝你好运。如果您认为这很困难并且会带来很多麻烦:正确,如果您的应用程序很小,最好将所有内容都转换为.NET Core / .NET Standard。



I am having trouble with switching partially to .NET Standard.

I am in the process of migrating a class library to .NET Standard, in this library I have the repositories and the database communication. I already migrated this successfully to use AspNetCore.Identity.EntityFrameworkCore. What I try to achieve is eventually having 1 .NET Standard project taking care of the database, where 1 MVC .NET Framework, 1 API .NET Framework and 1 new .NET Core application will be using it. Besides that a few other .NET Framework class libraries depend on it. Basically the .NET Core application has been made already but the back-end has not been 'merged' for overlapping functionalities.

Little overview:

Reason for not converting MVC/API to .Core is that too many other libraries currently depend on .NET Framework, some are not yet convertible, but using the same library for the database is a fundamental change which will avoid double implementations of some repositories.

I have also already converted my entities that implement Microsoft.AspNetCore.Identity.IdentityUser, Microsoft.AspNetCore.Identity.IdentityRole, etc. So my DbContext class looks like this:

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
}

I have successfully ran the EFCore Code First Migrations.

Now I am trying to configure the Identity in my MVC application (and then in the API project as well).

I just have the standard IdentityConfig.cs, Startup.Auth.cs where all the configuration is done. I have tried looking at this documentation (migration identity). All I could do is add this, where AddMvc() does not exist so that throws an compile error:

Startup.cs

using System;
using System.IO;
using Babywatcher.Core.Data.Database;
using Babywatcher.Core.Data.Entities;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Owin;
using Owin;

[assembly: OwinStartupAttribute(typeof(MyProject.MVC.Startup))]
namespace MyProject.MVC
{
    public partial class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            var services = new ServiceCollection();
            ConfigureAuth(app);
            ConfigureServices(services);
        }

        public void ConfigureServices(IServiceCollection services)
        {
            // Add EF services to the services container.
            services.AddDbContext<DatabaseContext>(options =>
                options.UseSqlServer(""));//Configuration trying to refer to above method: Configuration.GetConnectionString("DefaultConnection")

            services.AddIdentity<ApplicationUser, ApplicationRole>()
                .AddEntityFrameworkStores<DatabaseContext>()
                .AddDefaultTokenProviders();

            services.AddMvc();
        }
    }
}

Well I guess this doesn't really do much, Also I am using SimpleInjector throughout both .NET Framework projects which I would prefer to keep using if possible in stead of going to use the default dependency injector.

By adding above I don't really know what to do with the ConfigureAuth method and where to put all the configuration.

When I try to adjust the IdentityManager, to try and reference the same types within AspNetCore.Identity I start to get issues when trying to change the ApplicationUserManager:

Creating the UserStore is not a problem, but trying to create the UserManager is more difficult, I also have tried to use this in my UserRepository, like I did before, which I can't use now anymore :(.

Old 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"));
}

Attempting to do above again gives issues when creating the UserManager because of the 9 arguments it asks so I kind-of felt that this shouldn't be done this way... Probably going to do something like this to get them there of course I first want to fix the root problem.

Last but not least: Keep in mind that these applications are all in production already, so especially around the users I need to make sure that the logins all still work. When bringing this version live I will need to migrate the data to a new database because of some other migration issues.

解决方案

Alright so this is a long answer, be prepared to spent the next day on pulling your hair out of your head :).

First an interface of IApplicationUser which is implemented by 2 different classes:

public interface IApplicationUser
{
    string Id { get; set; }

    /// <summary>Gets or sets the user name for this user.</summary>
    string UserName { get; set; }
}

Implementation 1, this one is part of my database entities:

public class ApplicationUser :  IdentityUser<string>, IApplicationUser
{
    public DateTime? LockoutEndDateUtc { get; set; }
    public bool RequiresPasswordCreation { get; set; }
    public string TemporaryToken { get; set; }
}

Implementation 2, for my .NET Framework projects:

public class ApplicationUserMvc : IdentityUser<string, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>, IApplicationUser
{
    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUserMvc, string> manager)
    {
        // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
        var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
        // Add custom user claims here

        return userIdentity;
    }
 ...all the other things
}

I then created my own Identity Manager (interface)

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; }
}

Then my actual implementations of this, so this one is for my .NET Core projects.

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;
    }
}

The UserManager and RoleManager are injected on startup like so:

services.AddTransient<IIdentityManager, IdentityManagerCore>();

The .NET Framework implementation:

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;
    }
}

Last but not least you would need a seperate DatabaseContext for your .NET Framework project, this one will only be used for "identity" purposes, so not to actually query any data, just for authentication, authorization.

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();
    }
}

At this moment you should have all the classes necessary to use it everywhere. So for example, in your .NET Framework project, you can have your ApplicationUserManager like so:

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);
    }
  ...
}

In whatever Dependency Injection you use in .NET Framework, make sure to Register both your DatabaseContext and DatabaseContextMvc.

Here is my DatabaseContext which is inside the .NET Standard library and used across .NET Core and .NET Framework:

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);
    }

your focus is probably already gone after this long post or after implementing, but A few more words:

  • I can guarantee that with this you will make it work, it works perfect for the last half year.
  • So .NET Standard (and thus EntityFrameworkCore) is the primary way of doing database operations, most code is to cope with .NET Framework.
  • You will fight with installing the correct dependencies. It will cause runtime exceptions that you will encounter very quickly but easy resolvable, .NET Framework just needs to install the dependencies for itself. Make sure that the versions are aligned, use the Consolidate version under Manage NuGet packages for Solution (right-click on solution).
  • You will have to do it the-netcore-way for settings: so you need appsettings.json in your .NET Framework project as well. Also you still need it in the Web.Config, this is mostly for the small part of authentication.

    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
    }
    

  • Good luck. If you think this is difficult and causes a lot of trouble: correct, if you have a small application you are better of converting everything to .NET Core / .NET Standard.

这篇关于使用Identity Core的ASP.NET MVC框架中的身份的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆