asp.net核心身份simpleinjector注册applicationusermanager

时间:2017-07-05 13:24:55

标签: domain-driven-design asp.net-core-identity

我尝试隔离ASP.NET Core Identity版本1.1.2,架构DDD并创建一个CrossCutting层来为aspnet核心身份创建一个classlib,我使用SimpleInjector 4.0.8为我的IoC,所以我创建了一个类ApplicationUserManager和ApplicationSignInManager,但我不能在simlpleinjector容器中注册这个类

ApplicationUserManager

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,
        IServiceProvider services,
        ILogger<UserManager<ApplicationUser>> logger)
            : base(store, optionsAccessor, passwordHasher, userValidators, passwordValidators, keyNormalizer, errors, services, logger)
    {
        // My configurations stuffs were...
    }
}

和类 ApplicationSignInManager

public class ApplicationSignInManager : SignInManager<ApplicationUser>
{
    public ApplicationSignInManager(UserManager<ApplicationUser> userManager,
        IHttpContextAccessor contextAccessor,
        IUserClaimsPrincipalFactory<ApplicationUser> claimsFactory,
        IOptions<IdentityOptions> optionsAccessor,
        ILogger<SignInManager<ApplicationUser>> logger)
            : base(userManager, contextAccessor, claimsFactory, optionsAccessor, logger)
    { }

    // TODO: bug com tipo de retorno IdentityResult para ClaimsPrincipal
    //public override Task<ClaimsPrincipal> CreateUserPrincipalAsync(ApplicationUser user)
    //{
    //    return user.GenerateUserIdentityAsync((ApplicationUserManager)UserManager);
    //}
}

我尝试在 BootStrapper.cs 中注册此类

public static void RegisterServices(Container container)
    {
        // Infra.Data App Context
        // IdentityAppDbContext
        container.RegisterSingleton(() => 
        {
            var options = new DbContextOptions<IdentityAppDbContext>();
            return new IdentityAppDbContext(options);
        });

        // NetCore Identity
        container.RegisterSingleton<ApplicationUserManager>();
        container.RegisterSingleton<ApplicationSignInManager>();
        container.RegisterSingleton<IUserStore<ApplicationUser>>(() =>
        {
            var options = new DbContextOptions<IdentityAppDbContext>();
            return new UserStore<ApplicationUser>(new IdentityAppDbContext(options));
        });
        container.Register(() => (IOptions<IdentityOptions>)new IdentityOptions());
        container.RegisterSingleton<IPasswordHasher<ApplicationUser>>(() => new PasswordHasher<ApplicationUser>());

    }

但是当我运行aaplication返回错误说我需要注册表IOptions,IPasswordHasher和其他参与者类中的参数,问题是,如何才能注册这个类?

1 个答案:

答案 0 :(得分:1)

我有类似的要求:我的应用程序需要与身份进行交互(它基本上是关于人力资源,可能有自己的用户帐户),经过长时间的努力与各种问题在框架容器,我试图配置简单的注入器来提供所有身份服务。称之为疯狂,但这是它的工作原理(SimpleInjector 4.0和ASP.Net Identity Core 2.0.1):

这是“ConfigureServices”部分:

POSIXct

这需要在“配置”期间完成,否则密码重置和其他两个因素令牌内容将不起作用(运行时错误,尽管容器已经过验证)

// identity options are provided from outside, allowing configuration of the framework
container.RegisterSingleton<IOptions<IdentityOptions>>(new OptionsWrapper<IdentityOptions>(identityOptions));

// we rely on BCrypt instead of the default PBKDF2 hashing algorithm
container.Register<IPasswordHasher<MepUser>>(()=>new BCryptPasswordHasher(bcryptOptions));

// forwarding the framework logger to our own logging framework
container.Register<Microsoft.Extensions.Logging.ILoggerFactory, FrameworkToBackendFxLoggerFactory>();
container.Register(typeof(Microsoft.Extensions.Logging.ILogger<>), typeof(Microsoft.Extensions.Logging.Logger<>));

// identity store = a specific Entity Framework Core  DbContext, getting mapped into a specific db scheme
container.RegisterSingleton(identityDbContextOptions);
container.Register<MepIdentityDbContext>();

// UserStore<T> und RoleStore<T> both require a DbContext (no IdentityDbContext, neither a generic TDbContext)
// via constructor, but the container only knows about MepIdentityDbContext so we have to wire it manually
container.Register<IUserStore<MepUser>>(() => new UserStore<MepUser>(
                                                container.GetInstance<MepIdentityDbContext>(),
                                                container.GetInstance<IdentityErrorDescriber>()));
container.Register<IRoleStore<IdentityRole>>(() => new RoleStore<IdentityRole>(
                                                container.GetInstance<MepIdentityDbContext>(),
                                                container.GetInstance<IdentityErrorDescriber>()));

// framework internal services
container.Register<IdentityErrorDescriber>();
container.Register<ILookupNormalizer, UpperInvariantLookupNormalizer>();
container.Register<IPasswordValidator<MepUser>, PasswordValidator<MepUser>>();
container.Register<IUserValidator<MepUser>, UserValidator<MepUser>>();
container.Register<IUserClaimsPrincipalFactory<MepUser>, UserClaimsPrincipalFactory<MepUser>>();
container.Register<IRoleValidator<IdentityRole>, RoleValidator<IdentityRole>>();

// ASP.Net Core Identity violates a design decision of SimpleInjector: The API clearly differentiates the registration of collections
// https://simpleinjector.readthedocs.io/en/latest/decisions.html#the-api-clearly-differentiates-the-registration-of-collections
// By registering IEnumerables of those violating services with a simple wrapping single item array, Identity is happy
container.Register<IEnumerable<IUserValidator<MepUser>>>(() => new[] { container.GetInstance<IUserValidator<MepUser>>() });
container.Register<IEnumerable<IRoleValidator<IdentityRole>>>(() => new[] { container.GetInstance<IRoleValidator<IdentityRole>>() });
container.Register<IEnumerable<IPasswordValidator<MepUser>>>(() => new[] { container.GetInstance<IPasswordValidator<MepUser>>() });

// Role and UserManager reflect the API surface of the whole ASP.Net Core Identity framework
container.Register<RoleManager<IdentityRole>>();
// UserManagerShim is omitting (=nulling) the IServiceProvider parameter of UserManager<T>
container.Register<UserManager<MepUser>, UserManagerShim>();

虽然名称空间定义中出现// if you eagerly instantiate a provider instance that is considered being a singleton and // put it into the respective field in the TokenProviderDescriptor and list it in the option's // provider map, ASP.Net Core Identity will use this one instead of asking the IServiceProvider // instance injected into UserManager<T> (that we do not do, because it is bad design. Instead, // we just stuff null in there) identityOptions.Tokens.ProviderMap[TokenOptions.DefaultProvider] = new TokenProviderDescriptor(typeof(DataProtectorTokenProvider<MepUser>)) { ProviderInstance = new DataProtectorTokenProvider<MepUser>( dataProtectionProvider, new OptionsWrapper<DataProtectionTokenProviderOptions>(new DataProtectionTokenProviderOptions())) }; identityOptions.Tokens.ProviderMap[TokenOptions.DefaultEmailProvider] = new TokenProviderDescriptor(typeof(EmailTokenProvider<MepUser>)) { ProviderInstance = new EmailTokenProvider<MepUser>() }; ,但实际上并没有任何内容依赖于ASP.Net Core托管。对“外部世界”的唯一依赖是选项(POCO)和AspNetCore的实现,它将在ASP.Net场景中使用IDataProtectionProvider,但也可以使用{{1}来满足在测试中。

警告:KeyRing未被注入。这个课程完全混乱,取决于整个世界,所以我重写了它基本符合我的要求。您还失去了许多关于令牌提供程序的配置灵活性。但是,在我的情况下,这是你在设计时决定的一次,所以我很好。