如何注册自定义UserStore &DI中的UserManager

本文关键字:UserStore DI 中的 UserManager 自定义 何注册 注册 | 更新日期: 2023-09-27 17:50:42

设置如下:

public class ApplicationUser : IdentityUser<Guid>
{
}
public class ApplicationRole : IdentityRole<Guid>
{
}
public class ApplicationUserLogin : IdentityUserLogin<Guid>
{
}
public class ApplicationUserClaim : IdentityUserClaim<Guid>
{
}
public class ApplicationRoleClaim : IdentityRoleClaim<Guid>
{
}

下面是我的UserStore

的定义
public class ApplicationUserStore : UserStore<ApplicationUser, ApplicationRole, MyContext, Guid>
{
    public ApplicationUserStore(MyContext context, IdentityErrorDescriber describer = null)
        : base(context, describer)
    {
    }
}

下面是UserManager的定义

public class ApplicationUserManager : UserManager<ApplicationUser>
{
    public ApplicationUserManager(IUserStore<ApplicationUser> store, IOptions<IdentityOptions> optionsAccessor,
        IPasswordHasher<ApplicationUser> passwordHasher, IEnumerable<IUserValidator<ApplicationUser>> userValidators,
        IEnumerable<IPasswordValidator<ApplicationUser>> passwordValidators, ILookupNormalizer keyNormalizer,
        IdentityErrorDescriber errors, IEnumerable<IUserTokenProvider<ApplicationUser>> tokenProviders,
        ILoggerFactory logger, IHttpContextAccessor contextAccessor)
        : base(
            store, optionsAccessor, passwordHasher, userValidators, passwordValidators, keyNormalizer, errors,
            tokenProviders, logger, contextAccessor)
    {
    }
}
下面是我的DbContext的定义:
public class MyContext : IdentityDbContext<ApplicationUser, ApplicationRole, Guid>
{
    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);
    }
}

这里是startup。cs

    public IServiceProvider ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();
        services.AddEntityFramework()
            .AddSqlServer()
            .AddDbContext<MyContext>(options => options.UseSqlServer(Configuration.Get("Data:DbConnection")));
        services.AddIdentity<ApplicationUser, ApplicationRole>()
            .AddEntityFrameworkStores<MyContext, Guid>()
            .AddUserStore<ApplicationUserStore>()
            .AddRoleStore<ApplicationRoleStore>()
            .AddUserManager<ApplicationUserManager>()
            .AddRoleManager<ApplicationRoleManager>()
            .AddDefaultTokenProviders();
        var builder = new ContainerBuilder();
        builder.Populate(services);
        var container = builder.Build();
        return container.Resolve<IServiceProvider>();
    }

这个构造函数的依赖关系可以工作:

public AccountController(UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser> signInManager)

这个不会:

public AccountController(ApplicationUserManager userManager, SignInManager<ApplicationUser> signInManager)

谁知道我做错了什么?

如何注册自定义UserStore &DI中的UserManager

DI通常用于接口驱动的开发;.AddUserManager<ApplicationUserManager>()指定实现UserManager<>,而不是业务接口。这意味着它仍然期望你得到UserManager<ApplicationUser>,并且只这样使用它;它会给你一个ApplicationUserManager

我假设你有额外的方法,你想在你的ApplicationUserManager上使用。如果没有,就按它的工作方式使用依赖构造函数,享受接口驱动的开发。如果是,你有3个选择:

  1. 通过组合而不是继承使用扩展。与其继承UserManager<>,不如将ApplicationUserManager写成包装类;您可以将其包含在构造函数中。这应该为您提供ApplicationUserManager内部所需的所有功能。

  2. 按原样自己添加到DI框架中。这并不像听起来那么困难,因为UserManager<>本身没有实际状态:

    services.AddScoped<ApplicationUserManager>();
    

    这里的缺点是,对于用户的作用域,实际上有两个UserManager<>对象;因此可能会出现一些效率低下的情况。从目前的代码状态来看,我认为没有

  3. 写为扩展方法。如果您有许多依赖项,而不仅仅是UserManager<>的基本功能,这可能会非常复杂。

我现在使用ASP。. NET Core 1.1和此行为已修复。

我可以很容易地实现我自己的UserManager和UserStore,然后引导应用程序如下:

// identity models
services
    .AddIdentity<ApplicationUser, ApplicationRole>()
    .AddEntityFrameworkStores<ApplicationDbContext, Guid>()
    .AddUserManager<ApplicationUserManager>()
    .AddUserStore<ApplicationUserStore>()
    .AddDefaultTokenProviders();

和注入UserManager和UserStore到我的控制器,没有任何问题:

public AccountController(
    IIdentityServerInteractionService interaction,
    IClientStore clientStore,
    IHttpContextAccessor httpContextAccessor,
    ApplicationUserManager userManager,
    SignInManager<ApplicationUser> signInManager,
    IEmailSender emailSender,
    ISmsSender smsSender,
    ILoggerFactory loggerFactory)
{
    _interaction = interaction;
    _userManager = userManager;
    _signInManager = signInManager;
    _emailSender = emailSender;
    _smsSender = smsSender;
    _logger = loggerFactory.CreateLogger<AccountController>();
    _account = new AccountService(_interaction, httpContextAccessor, clientStore);
}

我想到了这个:

// Extract IApplicationUserManager interface with all methods you are using
public class ApplicationUserManager : UserManager<ApplicationUser>, IApplicationUserManager
// Register your custom user manager
services.AddIdentity<ApplicationUser, ApplicationRole>()
    .AddUserManager<ApplicationUserManager>();
// Return same scoped instance whenever you injecting your custom user manager into any constructor
services.AddScoped<IApplicationUserManager>(s => s.GetService<ApplicationUserManager>());