I am adding ASP.NET Identity authentication functionality to ASP.NET MVC 5 web application.
I am using Unity for dependency injection across the project, so I decided to inject dependencies required by the AccountController in the constructor:
public AccountController(UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser, string> signInManager)
{
_userManager = userManager;
_signInManager = signInManager;
}
My Login method is implemented as following (actually, I copied that code from an ASP.NET Web Application project template with Individual User Accounts authentication):
//
// POST: /Account/Login
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: true);
// Process result and return appropriate view...
// However, there are no authentication cookies in the response!
}
The problem is that authentication does not work correctly - even if I entered correct credentials and result is SignInStatus.Success, there are no authentication cookies being sent in the response.
However, if I use OWIN infrastructure to resolve ApplicationSignInManager instead of Unity container, everything works correctly:
//
// POST: /Account/Login
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
var owinSignInManager = HttpContext.GetOwinContext().Get<ApplicationSignInManager>();
var result = await owinSignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: true);
// Process result and return appropriate view...
// Authentication cookies are present in the response!
}
That's how ApplicationSignInManager is registered in application Startup class:
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
And this is ApplicationSignInManager declaration:
public class ApplicationSignInManager : SignInManager<ApplicationUser, string>
{
public ApplicationSignInManager(ApplicationUserManager userManager, IAuthenticationManager authenticationManager)
: base(userManager, authenticationManager)
{
}
public static ApplicationSignInManager Create(IdentityFactoryOptions<ApplicationSignInManager> options, IOwinContext context)
{
var userManager = new ApplicationUserManager(new UserStore<ApplicationUser>(new DatabaseContext()));
return new ApplicationSignInManager(userManager, context.Authentication);
}
}
Here's a part of my Unity configuration:
unityContainer.RegisterType<HttpContextBase>(new InjectionFactory(c => new HttpContextWrapper(HttpContext.Current)));
unityContainer.RegisterType<IOwinContext>(new InjectionFactory(c => c.Resolve<HttpContextBase>().GetOwinContext()));
unityContainer.RegisterType<IAuthenticationManager>(new InjectionFactory(c => c.Resolve<IOwinContext>().Authentication));
The idea is that Unity provides the same dependencies to the ApplicationSignInManager constructor as Create method does. But Unity's approach does not work for some reason: no authentication cookies being sent after successful log in.
This is very specific question, but maybe someone faced a problem like this before? I believe this behavior should be related to OWIN middleware, pipeline and how all that stuff is being wired up at the application startup.
Instead of registering IOwinContext in the container, do register IAuthenticationManager:
container.RegisterType<IAuthenticationManager>(
new InjectionFactory(c => HttpContext.Current.GetOwinContext().Authentication));
And have only one constructor for SignInManager:
public ApplicationSignInManager(ApplicationUserManager userManager, IAuthenticationManager authenticationManager)
I have done the registration with Unity like this, and here is the explanation.
Just in case you need to inject the RoleManager as well, here's how it's done with Unity:
container.RegisterType<IRoleStore<IdentityRole, string>, RoleStore<IdentityRole>>(new InjectionConstructor(typeof(MyDbContext)));
Don't forget to register IAuthenticationManager as well (see above answer).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With