Persisting claims across requests
Good question. Even made me do a little experiment.
This line:
AuthenticationManager.SignIn(
new AuthenticationProperties { IsPersistent = true }, identity );
Does not set a cookie. Only sets Identity
object for the later callback.
Cookie is only set when the control is passed to middleware and some OWIN internal method called Response.OnSendingHeaders
.
So your code is just adding claim2
on the identity
object that is stored in memory for later user. In theory you can even set claim1
after you have done the AuthenticationManager.SignIn
. And it will be persisted in the cookie anyway.
If you try to add a cliam like this in a controller:
public ActionResult AddNonPersistedClaim()
{
var identity = (ClaimsIdentity)ClaimsPrincipal.Current.Identity;
identity.AddClaim(new Claim("Hello", "World"));
return RedirectToAction("SomeAction");
}
This claim won't be set in the cookie and you will not see it in the next request.
If you'd like to have a deeper look how it all works, check out the source code of Katana Project, look on Microsoft.Owin.Security
and Microsoft.Owin.Security.Cookies
projects. Along with AuthenticationManager
in Microsoft.Owin.Net45
project.
Update
To answer your Edit 1 - IdentityUserClaim
is indeed persisted into the database and this is the way you can assign persisted claims to the user. You add these on the user through UserManager
await userManager.AddClaimAsync(userId, new Claim("ClaimType", "ClaimValue"));
This creates records in your database table that represents IdentityUserClaim. When next time user is logged in, these claims are read from the database and added to the identity and are available on ClaimsIdentity.Current
via property .Claims
or by method .HasClaim()
.
IdentityUserClaim
does not do anything else - just way to serialise Claim
object into the database. You don't usually access these directly, unless you want to go "bare knuckles" and write to that table yourself, outside of UserManager
.
To put it another way - Identity does not set the cookie. OWIN creates the cookie. Have a look on this piece of code:
public async Task SignInAsync(IAuthenticationManager authenticationManager, ApplicationUser applicationUser, bool isPersistent)
{
authenticationManager.SignOut(
DefaultAuthenticationTypes.ExternalCookie,
DefaultAuthenticationTypes.ApplicationCookie,
DefaultAuthenticationTypes.TwoFactorCookie,
DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie,
DefaultAuthenticationTypes.ExternalBearer);
var identity = await this.CreateIdentityAsync(applicationUser, DefaultAuthenticationTypes.ApplicationCookie);
identity.AddClaim(new Claim(ClaimTypes.Email, applicationUser.Email));
authenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
}
Here Authentication manager is part of OWIN. Identity
is part of System.Security.Claims
. All that belongs to Identity project is CreateIdentityAsync
method - that is basically converts user from the database into ClaimsIdentity
with all the persisted roles and claims.
To answer your Edit 2: You are correct, AspNet Identity is not part of Katana project, but Identity uses OWIN (part of Katana) for cookie handling and authorisation. Identity project mostly deals with user/roles/claims persistence and user management, like locking-out, user creation, sending emails with password resetting, 2FA, etc.
What was a surprise for me is that ClaimsPrincipal along with ClaimsIdentity and Claim are part of .Net framework that is available outside of OWIN or Identity. These are used not only in Asp.Net, but in Windows applications. Good thing that .Net now has open-source and you can browse through all these - gives you a better understanding how it all works together. Also if you are doing unit-testing, it is invaluable to know the internals, so you can stub-out all the functionality without using mocks.