I am using IdentityServer3 for authentication. All users are stored in Sql DB so I am also using Microsoft.AspNet.Identity
framework for actual authentication, and for the same purpose i have created my own ApplicationUserManager
class.
The AspNet identity has IoC feature integrated into OWIN middleware. and it registers the ApplicationUserManager
like:
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
it takes function delegate which returns a new instance of a ApplicationUserManager
public static ApplicationUserManager
Create(IdentityFactoryOptions<ApplicationUserManager> options,
IOwinContext context)
{
var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>()));
However, IdentityServer uses its own DI framework and (i think) we cannot use static Create()
method to rgister ApplicationUserManager
with IdentityServer, Also Create()
method takes IdentityFactoryOptions
and a IOwinContext
as parameters.
I followed this SO post and i change the implementation of ApplicationUserManager
to use Constructor Injection
public class ApplicationUserManager : UserManager<ApplicationUser, string>
{
public ApplicationUserManager(ApplicationUserStore store, IdentityFactoryOptions<ApplicationUserManager> options)
: base(store)
{
// Configure validation logic for usernames
UserValidator = new UserValidator<ApplicationUser>(this)
{
AllowOnlyAlphanumericUserNames = false,
RequireUniqueEmail = true
};
// Configure validation logic for passwords
PasswordValidator = new PasswordValidator
{
RequiredLength = 6,
RequireNonLetterOrDigit = true,
RequireDigit = true,
RequireLowercase = true,
RequireUppercase = true,
};
// Configure user lockout defaults
UserLockoutEnabledByDefault = true;
DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5);
MaxFailedAccessAttemptsBeforeLockout = 5;
EmailService = new EmailService();
SmsService = new SmsService();
var dataProtectionProvider = options.DataProtectionProvider;
if (dataProtectionProvider != null)
{
UserTokenProvider =
new DataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create("ASP.NET Identity"));
}
}
}
And then register all the services with IdentityServer's own DI framework as below
factory.UserService = new Registration<IUserService, UserService>();
factory.Register(new Registration<ApplicationUserManager>());
factory.Register(new Registration<ApplicationUserStore>());
factory.Register(new Registration<IdentityFactoryOptions<ApplicationUserManager>>(resolver => new IdentityFactoryOptions<ApplicationUserManager>
{
DataProtectionProvider = new Microsoft.Owin.Security.DataProtection.DpapiDataProtectionProvider("ASP.NET Identity")
}));
factory.Register(new Registration<ApplicationDbContext>(resolver => new ApplicationDbContext(ApplicationConfig.ConnectionString)));
Questions
ApplicationUserManager
with
IdentiServer's DI framework? DataProtectionProvider
during the registration and the UserTokenProvider
inside the constructor. How this 2 providers are being used by IdentityServer?IOwinContext
anywhere since
ApplicationUserManager's constructor does not need it anymore, will
that cause any issue down the OWIN pipeline?. ApplicationUserManager
?These two articles helped to solve my issue
http://tech.trailmax.info/2014/09/aspnet-identity-and-ioc-container-registration/
However my ApplicationUserManager
is in separate class library and startup.cs
is in web project. The class library does not have reference to the web project. So i refactored ApplicationUserManager
Constructor
public ApplicationUserManager(ApplicationUserStore store, IDataProtectionProvider dataProtectionProvider)
: base(store)
{
// other stuff
if (dataProtectionProvider != null)
{
UserTokenProvider =
new DataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create("UserToken"));
}
}
and also registered IDataProtectionProvider
with DI framework. I am not using Unity as IoC. I am using IdentityServer's own DI framework. So i register IDataProtectionProvider
as
factory.Register(new Registration<IDataProtectionProvider>(resolver => Startup.DataProtectionProvider));