簡體   English   中英

如何在 DI 中注冊自定義 UserStore & UserManager

[英]How to register custom UserStore & UserManager in DI

這是我的設置:

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)

任何人都知道我做錯了什么?

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM