English text: http://tech.trailmax.info/2014/08/aspnet-identity-and-owin-who-is-who/
Recently I found out There's a very good problem with Stackoverflow Questioner: Why can claim still be added to Identity and persisted to cookie s after calling Authentication Manager. SignIn?
The sample code is as follows:
ClaimsIdentity identity = UserManager.CreateIdentity(user, DefaultAuthenticationTypes.ApplicationCookie ); var claim1 = new Claim(ClaimTypes.Country, "Arctica"); identity.AddClaim(claim1); AuthenticationManager.SignIn(new AuthenticationProperties { IsPersistent = true }, identity ); var claim2 = new Claim(ClaimTypes.Country, "Antartica"); identity.AddClaim(claim2);
Yes, why claim2 is still available after cookie s have been set up.
After further study, I found that the AspNet Identity framework does not set cookie s, but OWIN does. OWIN is Katana Open Source Project Part of it. Active source usability is a good thing -- you can see why things work or don't work the way you expect them to.
In this case, I spent some time exploring the Katana project and AuthenticationManager It turns out that the SignIn method does not set cookies. It keeps the Identity object in memory until the time comes to set the response cookies, and then claims are transformed into a cookie. Everything works magically like this.
This raises another question. Identity has no open source code, so what role does OWIN play in Identity and how does Claims work?
It turns out that the Identity framework only deals with user persistence, password hashing, verifying that the password is correct, sending password reset emails, etc. But Identity does not actually validate users or create cookies. Cookies are processed by OWIN.
Take a look at the login code:
public async Task SignInAsync(Microsoft.Owin.Security.IAuthenticationManager authenticationManager, ApplicationUser applicationUser, bool isPersistent) { authenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie); ClaimsIdentity identity = await UserManager.CreateIdentityAsync(applicationUser, DefaultAuthenticationTypes.ApplicationCookie); authenticationManager.SignIn(new Microsoft.Owin.Security.AuthenticationProperties() { IsPersistent = isPersistent }, identity); }
Identity creates Claims Identity only. ReferenceSource Claims Identity is part of the. Net framework, not a nuget package from the Internet. Then the Claims Identity is passed to the Authentication Manager with an OWIN that sets cookies callbacks, and the Authentication Manager has a callback that sets cookies when writing the response header.
So far, so good, there are three parts: the Identity framework creates a Claims Identity, OWIN creates a cookie based on this Claims Identity, and. Net framework controls Claims Identity classes.
When accessing ClaimsPrincipal.Current in your class, you only use the. Net framework, and you don't need to use other class libraries. This is very convenient!
Default Claims
The Identity framework does a great job for you. By default, when you log in, it adds claims to a principal, as follows:
- User.Id: Type "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name identifier" or ClaimTypes.NameIdentifier.
- Username: Type "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name" or ClaimTypes.Name.
- "ASP.NET Identity": Save as "http://schemas.microsoft.com/access control service/2010/07/claims/identityprovider". This is very useful when you use OpenId for validation. But it's not very useful if you just use a database to store users. Click to see more information.
- Guid with user's secure postmark, persistent type in Claim is "AspNet. Identity. Security Stamp". A secure postmark is a major snapshot of user's status. If the password/method of authentication, email, etc. changes, the secure postmark will change, which allows you to "log out anywhere" from Kung by changing the certificate. Answer Get more information about secure postmarks.
- The most useful claims are roles. All roles assigned to users are saved as ClaimTypes. Roles or "http://schemas.microsoft.com/ws/2008/06/identity/claims/role". So next time you need to check the roles of the current user, check the claims, and not look up in the database, which is very fast. In fact, if you call Claims Principal's. IsInRole("RoleName"), the framework will enter claims and Check whether the user has assigned the role of the specified value.
You can be there. .Net Reference Look at these claim types on the website. This list is not complete. You can create your own claim type -- that's a string.
If you want to add your own owin claim type, I recommend that you use your own symbols, such as "MyAppplication:GroupId", and keep all claim types as constants in one class:
public class MyApplicationClaimTypes { public string const GroupId = "MyAppplication:GroupId"; public string const PersonId = "MyAppplication:PersonId"; // other claim types }
In this way, you can always find claims and do not conflict with the claim type in the framework unless your claims are exactly the same as the claims type in the framework, such as ClaimTypes.Email.
Add default claims
I always add user email to the claims list in the user login, just like claim1 and claim2 in the previous example:
public async Task SignInAsync(IAuthenticationManager authenticationManager, ApplicationUser applicationUser, bool isPersistent) { authenticationManager.SignOut( DefaultAuthenticationTypes.ExternalCookie, DefaultAuthenticationTypes.ApplicationCookie); var identity = await this.CreateIdentityAsync(applicationUser, DefaultAuthenticationTypes.ApplicationCookie); // using default claim type from the framework identity.AddClaim(new Claim(ClaimTypes.Email, applicationUser.Email)); authenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity); }
You can add default claims for all user s here, but there is an IClaimsIdentityFactory class (assigned to UserManager) with only one method:
public interface IClaimsIdentityFactory<TUser, TKey> where TUser : class, IUser<TKey> where TKey : IEquatable<TKey> { /// <summary> /// Create a ClaimsIdentity from an user using a UserManager /// </summary> Task<ClaimsIdentity> CreateAsync(UserManager<TUser, TKey> manager, TUser user, string authenticationType); }
The default implementation of AspNet Identity is to create Claims Identity, add the default claims mentioned above, and store Identity user Claims type claims in the database for users. You can rewrite this implementation and insert your own logic/claims:
public class MyClaimsIdentityFactory : ClaimsIdentityFactory<ApplicationUser, string> { public override async Task<ClaimsIdentity> CreateAsync(UserManager<ApplicationUser, string> userManager, ApplicationUser user, string authenticationType) { var claimsIdentity = await base.CreateAsync(userManager, user, authenticationType); claimsIdentity.AddClaim(new Claim("MyApplication:GroupId", "42")); return claimsIdentity; } }
Then assign UserManger:
public UserManager(MyDbContext dbContext) : base(new UserStore<ApplicationUser>(dbContext)) { // other configurations // Alternatively you can have DI container to provide this class for better application flexebility this.ClaimsIdentityFactory = new MyClaimsIdentityFactory(); }