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