I'm using ASP.NET identity with a ClaimsIdentity
to authenticate my users. When a user is authenticated, the property User.Identity
contains a ClaimsIdentity
instance.
However, this is not the case during the Login request:
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if (!ModelState.IsValid)
{
return View(model);
}
var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, false, shouldLockout: false);
switch (result)
{
case SignInStatus.Success:
var identity = User.Identity;
------------> // identity is of type WindowsIdentity <------------
return RedirectToLocal(returnUrl);
As you can see, even though the login was successful, the property User.Identity
is not yet set to the ClaimsIdentity
instance. I think this is plausible, it means that the SignInManager
does not update the property, so we have to wait until the next request to see the result of the login.
However, I have to do additional logic after the method PasswordSignInAsync
, so I need a way to get the ClaimsIdentity
instance in the .Success branch of the switch statement.
While inspecting the SignInManager
in the debugger, I saw that it is of type Microsoft.Owin.Security.AuthenticationManager
, which has the property SignInEntry.Item1
which contains the ClaimsIdentity
I'm looking for.
However, the type Microsoft.Owin.Security.AuthenticationManager
is not public, so the only way seems to be a hack using reflection.
Is there an better way?
The ASP.NET Identity UserManager class is used to manage users e.g. registering new users, validating credentials and loading user information. It is not concerned with how user information is stored. For this it relies on a UserStore (which in our case uses Entity Framework).
Now, open the Startup configurations and add below code under ConfigureServices. This code will setup the database context. The second line configures the database which should be used for identity. AddIdentity(IServiceCollection) adds the default identity system configuration for the specified User and Role types.
I agree that it's too bad that the PasswordSignInAsync doesn't return the user instance as an out parameter. If you look the source code, you can see that it uses this.UserManager.FindByNameAsync(userName)
to find the user by userName, and then uses this.UserManager.CheckPasswordAsync(user, password)
to validate the password, but the user is stored in a local variable.
I think this should be proposed as an improvement to the SignInManager class.
A possible (and inefficient) workaround is to query for the user again and then create the claims identity yourselft in the same way SignInManager.SignInAsync does:
ApplicationUser user = await UserManager.FindByNameAsync(model.Email);
ClaimsIdentity claimsIdentity = await SignInManager.CreateUserIdentityAsync(user);
The identity is exposed through the AuthenticationResponseGrant
property:
ClaimsIdentity identity = SignInManager.AuthenticationManager.AuthenticationResponseGrant.Identity;
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