The ASP. NET core identity is the membership system for building an ASP. NET core Web application, including membership , login, and user data storage
This is an official introduction from the ASP. NET Core Identity Warehouse Home page, if you are a new and you may not understand what membership is, let me explain that membership is translated by membership , membership has membership, Membership, membership and other relevant meanings, we can be simple and direct but not very appropriate to understand the user management system
The ASP. NET Core Identity (hereinafter referred to as identity), since it can be understood as a user management system, then she is naturally very powerful, including all aspects of user management, in simple terms include:
- User data storage (using any of your favorite relational databases, from Sqllite to MySQL, SQL Server, etc., supported by entity Framwork)
- Login, register plus identity authentication (cookie-based authentication, if you use VS, you can also generate a user interface and process code for registering logins)
- Role management
- Claims-based authentication mode Claims Based authentication(If you don't know what claim is, it's okay to remember the word first)
OK identity so good, what exactly does she look like? How do I use it, then we'll do a little demo experience, while doing, while explaining
Software preparation
- Visual Studio 2017 (the newer the better, if you don't have to download the Vs2017 Community Edition, the installation is fast, compatible with the old version, completely free portal)
Hands-on.
Open VS's Create new project panel select. NET Core, ASP.
Select Web application (Model View Controller)--Change identity--Personal user account
After that, the SQL Server Compact is used by default to store user data
By Ctrl+F5
running the project
Notice the register and login in the upper-right corner? The identity is automatically added to the project when we choose Personal Authentication , and it generates
- Account Controller (
AccountController
registration and login-related codes are here)
- Login Registration page (Other such as: confirmation email, access restrictions, etc.)
- Management Controller (
ManageController
This is for registered users, mainly has two functions, change password and two-factor authentication)
- Identity doesn't give you an admin interface.
Click Register to enter the registration interface, the interface looks good, even can be used directly, and then we register an account
When you click on the Register button, you will be redirected to the database migration (if you have used EF Core, you will not feel unfamiliar with this concept) confirmation page
After the app is migrated, you'll have to wait a moment to refresh the page, and during that time, I suggest you look at the information on the migration page
If you don't understand, see
OK, after the migration, you will be back to the homepage, the upper right corner of the registration will become your mailbox and logout link, click on your account mailbox, first see what's Inside
The content of this page is in ManageController
, if you do not know what the two-factor authentication Two-factor Authentication is, it's okay, in the subsequent talk about it
Click the Send verification email
link, don't worry, don't really send the message
Identity provides e-mail authentication, which is usually the kind of message that has an encrypted link to verify the message, how to generate the link, the identity is already done, and even writes the interface for sending the message-- IEmailSender
and an empty implementationEmailSender
namespace IdentityDemo.Services{ public interface IEmailSender { Task SendEmailAsync(string email, string subject, string message); }}
View Database
Just now we have registered a new user, then where does the user save? The default storage is SQL Server Compact, and then we find it and see how identity Designs User data, and I think it's best to learn a new technology by first looking at what it does to save the data.
Connect to the database by selecting Tools, in the menu above vs
Ok, where is the default database location? What's the name of the database? Now, close this window and open the configuration file under the project root directory appsettings.json
{ "ConnectionStrings": { "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=aspnet-IdentityDemo-E3266F7D-D9FD-4038-9AF7-773A31FC3680;Trusted_Connection=True;MultipleActiveResultSets=true" }, "Logging": { "IncludeScopes": false, "LogLevel": { "Default": "Warning" } }}
We can see the name of our database aspnet-IdentityDemo-E3266F7D-D9FD-4038-9AF7-773A31FC3680
, and his position is C:\Users\{当前登录的用户名}\
below. Do it again, then click Continue to select your database file
This may encounter a situation where the database file is occupied
This is because the program that just started does not exit, if you are using self-hosted boot, then close it if you use iisexpress, also close it
All right, let's see what's in the database.
_EFMigrationsHistory
The Migration history table for EF doesn't have to follow this table
AspNetUserClaims
, AspNetRoleClaims
is the user and role of the Declaration table, before we mentioned that the Identity is based on the Claims authentication mode (Claims Based authentication), claim in which plays a very important role, Even roles are converted into Claim,claim related will be explained later, if you do not understand it, do not worry
AspNetUsers
, AspNetRoles
and AspNetUserRoles
Store user and role information
AspNetUserTokens
, AspNetUserLogins
stored in the user's use of the external login provider's information and tokens, external login provider refers to such as microblogging, QQ, Google, Microsoft, such as the provision of OAuth or OpenID connect to the manufacturer. For example, Segmentfault can use Weibo to login
And then we're going to explain the most important table.AspNetUsers
User Data Core Storage--aspnetusers
The actual data for the newly registered user is as follows
Blog Park does not support the horizontal scrolling code, so I put the code to come up, looking a bit awkward or you can go here to see the specific data
Id------------------------------------d4929072-e704-447c-a9aa-e1b7f510 Fd37 accessfailedcount-----------------0 concurrencystamp------------------ ------------------5765da8f-1945-40c6-8f81-97604739e5ec Email-----------------[email protected] Ema Ilconfirmed--------------0 lockoutenabled--------------1 lockoutend----------NULL Normaliz Edemail-----------------[email protected] Normalizedusername------------------[email protected] PasswordHash-------------------------------------- ----------------------------------------------aqaaaaeaaccqaaaaehq+ 3z9h0tiusinnps8b99skaqbxh0zcwlgwtgtvik6s85viewqfv8tf8brydtw8rw==phonenumber-----------NULL Phonenumberconfirmed--------------------0 Securitystamp------------------------------------a4d9c858-cc08-4ceb-8d5d-92a6cb1c40b8twofactorenabled----------------0 UserName--- --------------[email protected]
Id
The primary key defaults to nvarchar (450) but is actually the stored GUID string, and it is worth mentioning that the ID is created at the time
The GUID of the primary key is generated in the constructor when the user is created
namespace Microsoft.AspNetCore.Identity{ public class IdentityUser : IdentityUser<string> { public IdentityUser() { Id = Guid.NewGuid().ToString(); }
This is a small piece of source code, to prove the above content
That is, it is a completely random unordered GUID, then it may be the hidden danger is that when the user is very large, the creation of the user may be slow, but for the vast majority of scenarios, it is unlikely (there are so many users), of course, this may happen, so in subsequent articles, I'll explain how to use bigint as the primary key
Accessfailedcount
This is used to record the number of times a user attempts to log in but failed to log on, and we can use this to determine when to lock the user.
Concurrencystamp
The synchronization token, which must change the value of this column whenever the user record is changed, actually stores the GUID, and initializes the random value directly on the property when the user model is created
public virtual string ConcurrencyStamp { get; set; } = Guid.NewGuid().ToString();
Also note that the value of this column is changed by the time it is manually written in the program, not by the database change (perhaps considering that not all EF-supported databases support timestamp or rowversion types)
Email, Normalizedemail
E-mail is email,normalizedemail is standardized email
What is normalization?
In the user we just created, you can see that normalizedemail just turns the value of email into uppercase, and I think you've got it all figured out.
Indeed, this will improve the efficiency of the database query, from the identity of the code can be seen, about the email query has been converted to Normalizedemail query. Word ..., let's look at a short piece of code.
namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore{ public override Task<TUser> FindByEmailAsync(string normalizedEmail, CancellationToken cancellationToken = default(CancellationToken)) { // 略... return Users.FirstOrDefaultAsync(u => u.NormalizedEmail == normalizedEmail, cancellationToken); }
NormalizedEmail
You don't have to worry about it when you use it, and you don't have to change its value manually because it's automatically updated when users create or update their profile . NormalizedEmail
And then we still take a look at the source code code
namespace Microsoft.AspNetCore.Identity{ public class UserManager<TUser> : IDisposable where TUser : class { public virtual async Task<IdentityResult> CreateAsync(TUser user) { // 略... await UpdateNormalizedUserNameAsync(user); await UpdateNormalizedEmailAsync(user); return await Store.CreateAsync(user, CancellationToken); } protected virtual async Task<IdentityResult> UpdateUserAsync(TUser user) { // 略... await UpdateNormalizedUserNameAsync(user); await UpdateNormalizedEmailAsync(user); return await Store.UpdateAsync(user, CancellationToken); }
UserName, Normalizedusername
Username is username Normalizedusername or username after normalization, that is, converting to uppercase
Their behavior and the above-mentioned Email, normalizedemail consistent, do not repeat the
Emailconfirmed
The message has been confirmed, this is a bit (bool) type of column, the previous article refers to the identity contains the send and verify the confirmation message function, when the user is created by default, this value is false, confirm that the link is generated by identity, and then sent to Iemailsender. Ok, half of the tasks are done here, and a little piece of code will give you a clearer picture of the process.
public async Task<IActionResult> Register(RegisterViewModel model, string returnUrl = null){ //略... var user = new ApplicationUser { UserName = model.Email, Email = model.Email }; var result = await _userManager.CreateAsync(user, model.Password); if (result.Succeeded) { var code = await _userManager.GenerateEmailConfirmationTokenAsync(user); var callbackUrl = Url.EmailConfirmationLink(user.Id, code, Request.Scheme); await _emailSender.SendEmailConfirmationAsync(model.Email, callbackUrl); 略...
The code is generated when the project is created and belongs to your project, not the identity.
You may think that after registering we have successfully entered the system, and has not been blocked, even if we did not confirm the mail, the data in the database also indicates that the message is not confirmed
Indeed, because this is not in the identity of the scope, this is our program logic, to prevent unauthenticated mail users to log in, we need to do, but, very simple, only need to write a few lines of code at the time of landing, here for the moment not to start the discussion
Lockoutenabled, Lockoutend
Their data type is bit and DateTimeOffset (7), lockoutenabled Indicates whether this user can be locked, lockoutend specifies the expiration date of the lock, null or a past time, which means that the user is not locked
It is important to note that the identity provides us with the infrastructure for locking, but it is the logic of our program to prevent users from logging in after the user has been locked out.
PasswordHash
Password hash, the identity of the use of the hash strength is relatively high, the difficulty of brute force is very large
=======================HASHED PASSWORD FORMATS=======================Version 2:PBKDF2 with HMAC-SHA1, 128-bit salt, 256-bit subkey, 1000 iterations.(See also: SDL crypto guidelines v5.1, Part III)Format: { 0x00, salt, subkey }Version 3:PBKDF2 with HMAC-SHA256, 128-bit salt, 256-bit subkey, 10000 iterations.Format: { 0x01, prf (UInt32), iter count (UInt32), salt length (UInt32), salt, subkey }(All UInt32s are stored big-endian.)
Version 2 and 3 are for compatibility with identity V1 V2 and V3 their correspondence is as follows
- V1, v2, Version 2
- Version 3, v3
Securitystamp
The security token, a random value, must change the value of this item when the user credential-related content changes, the fact that the GUID is stored
The timing of this change is:
- User-Created
- change user name
- Remove external Login
- Set/Change Message
- Set/Change phone number
- Set/Change two-factor verification
- Change Password
ConcurrencyStamp
SecurityStamp
is also changed by code control in the program.
PhoneNumber, phonenumberconfirmed
Telephone and telephone confirmed, easy to understand
Twofactorenabled
Indicates whether the current user has two-factor authentication turned on
This is the end of the first experience:)
This article has been synced to my segmentfault column. NET core Web Dev
ASP. NET Core Identity hands on (1)--identity first Experience
ASP. NET Core Identity hands on (1)--identity first Experience