In this article, we are going to learn about ASP.NET Core Identity implementation in the ASP.NET Core project.
ASP.NET Core Identity is the membership system for web applications that includes membership, login and user data.
But, it is not just a user store, it is much more than that.
Instead of being just a simple database schema, it contains a great variety of helper functionalities that can aid us in the user management process. In this article, and through this series as well, we are going to learn more about the different functionalities this library provides.
To navigate through the entire series, visit the ASP.NET Core Identity series page.
Starting Project Overview
We are using the ASP.NET Core 3.1 web application project with no authentication template because we want to do it by ourselves, from scratch.
We use EF Core to communicate with the database, and if you want to learn more about it, we have a great series about Entity Framework Core that explains all the steps we’ve used in this application.
This application runs migrations automatically, so all you have to do is to start the project. We’ve also added the Employees action in the Home controller:
public async Task<IActionResult> Employees() { var employees = await _context.Employees.ToListAsync(); return View(employees); }
And modified the _Layout
view from the Privacy
link to the Employees
link:
<li class="nav-item"> <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Employees">Employees</a> </li>
And, that is it. Once we start our project and navigate to the Employees link, we are going to see a list of employees:
ASP.NET Core Identity Implementation
The first thing we need to do is to install the Microsoft.AspNetCore.Identity.EntityFrameworkCore
library:
This library is going to help us integrate ASP.NET Core Identity with the existing EF Core project.
After the installation finishes, let’s create a new User
class in the Models
folder:
public class User : IdentityUser { public string FirstName { get; set; } public string LastName { get; set; } }
Our class inherits from the IdentityUser
class provided by the ASP.NET Core Identity. If we inspect the IdentityUser
class, we can see that it inherits from the IdentityUser<string>
class:
public class IdentityUser : IdentityUser<string> { public IdentityUser(); public IdentityUser(string userName); }
If we inspect the generic IdentityUser
class as well, we are going to find all the different properties that will be added to our table in the database:
So basically, with the User
class, we extend the IdentityUser
class with two additional properties. These properties will be added to the database as well.
If you are satisfied with properties from the IdentityUser<TKey>
class, you don’t have to create an additional User
class. Otherwise, if you wish to extend it, this is a way to do it.
Now, let’s continue with the ApplicationContext
class modification:
public class ApplicationContext : IdentityDbContext<User> { public ApplicationContext(DbContextOptions options) : base(options) { } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.ApplyConfiguration(new EmployeeConfiguration()); } public DbSet<Employee> Employees { get; set; } }
So, our class now inherits from the IdentityDbContext
class and not DbContext
because we want to integrate our context with Identity. Additionally, we call the OnModelCreating
method from the base class. This is required for the migration to work properly.
A Bit More About Extending the Schema
At this point, we know how to extend the Identity schema but we should always think about it beforehand. It is quite a common process to add additional data to a user and there are two ways of doing that. By using claims and by adding additional properties in a class.
While using claims, we populate the Claim object by providing the type and the value properties of the string type (new Claim(string type, string value)). But if we have something more complex, we should use a custom property. Additionally, both ways are searchable but the custom properties are a way to go if we search a lot.
So for our example, we could have used the claims instead of adding the User
class, but, we wanted to show you how to extend an Identity model in your project.
Now, let’s move to the configuration part.
ASP.NET Core Identity Configuration
We can register ASP.NET Core Identity with two extension methods: AddIdentityCore<TUser>
and AddIdentity<TUser, TRole>
.
The AddIdentityCore
method adds the services that are necessary for user-management actions, such as creating users, hashing passwords, password validation, etc. If your project doesn’t require any additional features, then you should use this method for the implementation.
If your project requires those features and any additional ones like supporting Roles not only Users, supporting external authentication, and SingInManager, as our application does, you have to use the AddIdentity
method.
Of course, we can achieve the same result with the AddIdentityCore
method, but then we would have to manually register Roles, SignInManager, Cookies, etc.
That said, we are going to use the AddIdentity
method for our registration in .NET 5 and previous versions:
public void ConfigureServices(IServiceCollection services) { services.AddDbContext<ApplicationContext>(opts => opts.UseSqlServer(Configuration.GetConnectionString("sqlConnection"))); services.AddIdentity<User, IdentityRole>() .AddEntityFrameworkStores<ApplicationContext>(); services.AddControllersWithViews(); }
In the .NET 6 and later versions, we have to modify the Program class:
builder.Services.AddDbContext<ApplicationContext>(opts => opts.UseSqlServer(Configuration.GetConnectionString("sqlConnection"))); builder.Services.AddIdentity<User, IdentityRole>() .AddEntityFrameworkStores<ApplicationContext>(); builder.Services.AddControllersWithViews();
So, next to the AddIdentity method call, we add the AddEntityFrameworkStores
method to register the required EF Core implementation of Identity stores.
Creating Additional ASP.NET Core Identity Tables
With all of these in place, we can add additional tables to the database. To do that, we are going to create a new migration:
PM> Add-Migration CreatingIdentityScheme
And apply it as well:
PM> Update-Database
Once we have done that, we can check our database:
We can see the Employees table from the initial migration and all the other tables from the new migration. Additionally, if we expand the AspNetUsers
table, we are going to find our additional properties:
Excellent job.
The one last thing, we have to do is insert some initial roles in the database.
Adding Roles to the Database
Having initial roles in the database is a quite common process, so let’s do that.
In the Configuration
folder, we are going to create an additional class:
public class RoleConfiguration : IEntityTypeConfiguration<IdentityRole> { public void Configure(EntityTypeBuilder<IdentityRole> builder) { builder.HasData( new IdentityRole { Name = "Visitor", NormalizedName = "VISITOR" }, new IdentityRole { Name = "Administrator", NormalizedName = "ADMINISTRATOR" }); } }
And then modify the OnModelCreating
method:
protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.ApplyConfiguration(new EmployeeConfiguration()); modelBuilder.ApplyConfiguration(new RoleConfiguration()); }
Finally, let’s create and apply the migration:
PM> Add-Migration InsertedRoles
PM> Update-Database
This is the result:
And just like that, we have prepared everything we need.
Conclusion
That is it for now. We have seen that ASP.NET Core Identity implementation is not such a complex thing, once we know how to do it.
Through this article, we’ve used the name ASP.NET Core Identity a lot and that’s because this is the name of this library, not Identity Server or Identity Framework or anything similar.
Additionally, it is important to mention that ASP.NET Core Identity is a different thing from the Identity Server. ASP.NET Core Identity is a user store whilst the Identity Server offers protocol support for Open ID Connect.
A lot of people mix these terms up.
In the next article, we are going to talk about the user registration process and how to change the rules which ASP.NET Core Identity provides out of the box.
it would be nice if we had 2 new guides for .net 8 one for mvc and the like and another for web api
thanks
What if I do not want to use the UI provided by scaffolding but just an only api approach of identity. What would be the best strategy?
Hi. Well, you don’t have to scaffold those UI pages at all. In this entire series, we are creating our custom UIs and using only Identity API for auth.
Even this article is quite old, I have to tell you guys, you having the best and clearest articles about .net on the www. I love reading your articles and you are most time the first place if I am try to learn a new technique.
Hi Patrick. Thank you for the kind words. Yes, this article uses a bit older version of .NET and Identity, but, we are checking that with each .NET update and as you can see, we even provided differences with code snippets to cover newer versions. In the core of Identity, nothing really changed that much. So all the articles in the series are pretty much valid. I can tell that because we are updating our books for each .NET version and I don’t remember that we had to change anything regarding identity (unless something drastically changed in the last couple of months).
Sounds great, keep it up
Quick Note – Just want to clarify in your writeup above you wrote …If you are satisfied with properties from the
IdentityServer<TKey>
class, you don’t have to create an additionalUser
class. Otherwise, if you wish to extend it, this is a way to do it.I thought your purpose here was to not use IdentityServer and this seems out of place in relation to the code examples Did you mean to say IdentityUser a this point
Hi Dave. Yeah, this is a typo. We are working with IdentityUser<TKey> and it should be User not Server, my bad here. Sorry for that. I will fix that now.
Thank you for the Awesome tutorial, learned alot. Hoping you can make a tutorial on how to use dapper with identity in the future.
Hi Jayce. I’m so glad you like it. About your request, we don’t have any article on that specific topic but in our book package: https://code-maze.com/ultimate-aspnetcore-webapi-second-edition/?source=nav, we have a bonus book Dapper with ASP.NET Core Web API, where we cover all the things from the main book but just with Dapper instead of EF Core. There, we also cover how to use Dapper with ASP.NET Core Identity. On the shared link, you can find TOC for each book.
This article is very useful to me while I am developing a web application first time by using ef core/.net 6 and db first operation.
However, I had a problem that the AspNetRoles table contents (Id) always changed when I executed Update-Database instruction each time. So I comment (//) the codes:
modelBuilder.ApplyConfiguration(new RoleConfiguration()); in the ApplicationContext.cs file. It seemed the role id wouldn’t change any more.
Then I implemented the whole related Identity functions, including registration, user-login, add-to-role etc. Thanks to a series of the articles you wrote. I appreciate it.
Later I found an issue let me a little frustrated and couldn’t find the proper solution for a long time. My colleagues and I used git tools to maintain the application codes. When my colleagues updated/added some table contents and executed Add-Migration / Update-Database instructions, the data of AspNetRoles and AspNetUserRoles tables were all cleared each time. Then I needed to restore the role data by executing modelBuilder.ApplyConfiguration(new RoleConfiguration()) again and re-builded the web application and then commented this line (codes) again. The operations really looked like stupid.^^
I had searched the related keywords many times in vain from google or stackoverflow.com.
So I would like to ask help from you. Would you know how to solve this issue?
Hello Jerry. Well, I don’t know what to say here. Just one thing, make sure that when you create a new migration file always check it to see if there is anything that clears the Roles tables. Also, you can inspect the RepositoryContextModelSnapshot file and see if it assigned different Ids to AspNetRoles table. I had an issue like that when we were writing our ASP.NET Core book.
Ok. Thank you.
Finally, I got the reason why.
I restored the original role data by the codes ‘modelBuilder.ApplyConfiguration(new RoleConfiguration()‘ and executed Add-Migration / Update-Database instructions. Then I found the AspNetRoles contents was a little different from other tables in the Snapshot file. There were role data: ‘Has Data ( new { Id = “xxx”, Name = “xxx”…} )‘ following the codes ‘b.ToTable(“AspNetRoles”, (string)null)’.
Each time other people executed the migration instructions and ‘Has Data (…)’ would be deleted automatically and then I found the role data in DB were also all gone.
So I restored the role data by backup sql file in DB instead of executing the ApplyConfiguration codes. Thus there were no ‘Has Data (…)’ in the Snapshot file. The process of executing migration instructions would not have an influence on the role data in DB anymore. That’s it. :))
Thanks a lot, Jerry for sharing the info with us.
I see many examples that extend the IdentityUser instead of creating a new object/table for custom properties. Conceptually, I like the idea of keeping the authentication data separate from the custom properties. Different types of users can have different types of custom properties.
Good Article
Thanks. I’ve tried to add the modifications for .NET 6 and later, and still leave the implementation for .NET 5 and previous versions. I think this way, we’ve covered all the readers using older or newer versions. If you are using .NET 6, and can’t see the code for .NET 6, just try clearing the cache on the page CTRL+F5
new EmployeeConfiguration() the type or name space could not be found i dont know where to place it 😀
Hello Oscar. You can always download our source code – we’ve provided that at the top of the article (red box). Also you can find the class here: https://github.com/CodeMazeBlog/identity-aspnetcore/tree/introducing-identity-aspnetcore/IdentityByExamples/IdentityByExamples/Models/Configuration
Hi Marinko,
I could not populate the roles table with the EntityTypeConfiguration data.; `Add-Migration` worked, but `Update-Database` returned: “There is no entity type mapped to the table ‘AspNetRoles’ used in a data operation. Either add the corresponding entity type to the model or specify the column types in the data operation”. I am using the web api project, instead of this tutorial’s repo.
Is it possible that updates to Core Identity are causing this problem or is it more likely that it’s something I’ve done differently/wrong?
Hello mc alex. I am not sure about all the updates regarding the identity, but we were using the same technique in our Web API book with .NET5 and it works without a single problem. I am not aware of your code, but have you provided the correct entity type for the IEntityTypeConfiguration interface and for the EntityTypeBuilder class?
I have the paid book and having the exact same problem noted above.
Please use the source code provided with the book. I personally wrote all the code from all the books of the premium edition, and I didn’t face this type of issue. Again, feel free to use the source code and compare your code with it. This is the easiest way to solve your issue.
Hello Sir,
In the example, we inherit from IdentityDbContext instead of dbContext.
So if I am using ASP.NET Core Identity in my project, does that mean I would have no use for dbContext, instead just use IdentityDbContext for all my contexts?
I must admit I didn’t have such a case with multiple db context and using ASP.NET CORE Identity in that project. I believe you don’t have to use it for all contexts but again as I said, didn’t face such a situation. Why don’t you try it, some dummy project, and help us all with your solution 😉
Most definitely I agree with you – yes, just one database context in a project. Thanks again for the quick response!
It’s important remember that IdentityDbContext inherit from DbContext. It’s just add the necessary to Identity. In other words: even you use IdentityDbContext you’ll still using DbContext.
Well done. I’m following this tutorial along and so far so good, even though I’m using .net core 3.1
Thank you Erick. I hope you will lear a lot of useful things until the end of this series. And just ot mention, this series was built in ASP.NET Core 3.1. So, it must work with your project 🙂
Life saver
I really hope you will find entire series useful as well (once we finish it 🙂 ) Thank you very much. Best regards.
Hi;
For my new project, I need to use MongoDB than relationDB that is supported by EF. So, there is no EF, and relationalDB to store all the identity tables.
What’s the suggestion approach to use Identity like IdentityServer4 with MongoDB?
Hello Ben. Well, I didn’t use MongoDB with Identity Server4,so I’m not the best person to give you that kind of advices. But database is a database whether it is relational or not. You need to have your user store in db, so I believe you will have to create that structure in the MongoDB manually and then just use any MongoDB driver to connect your ASP.NET Core app with it. Identity has nothing to do with that part. I’ve found this link so maybe this can help you. Best regards Ben.
Hi;
I understand that DB doesn’t play a role, however the ASP.net Identity relies on Entity Framework to function properly. So if I was using MySQL it would work because EF supports MySQL driver. However EF does NOT support Document DB like MongoDB, and that was my point related to EF part.
Well, as I said, I didn’t work with IS4 and Mongo. So I’ve tried to help you somehow. But obviously I didn’t.
Oh no, don’t take it in a wrong way. I was just clarifying my challenge.
Thanks for your help anyway.
It’s my plesure. Once you solve your challenge, since it sounds like an interesting one, if you desire to make a blog post out of your solution, we would gladly accept it and host it on our site. This sounds as something that can help a lot of readers out there. We are always open for new ideas and new people to work with 😀 Have a great day Ben (well at least in my time zone is still a day 😀 )
Thanks, yes I’m in US, eastern time zone.
At this stage, I’m contemplating whether I should maintain the users’ profile and identity on IS4, as it is a big risk or use Azure B2C or Okta for auth.
If I end up going with IS4, I might keep the user’s identity tables in MSSQL DB and take advantage of EF and IS4 and use MongoDB as my app db. This way, I don’t need to reinvent the wheel maintaining MongoDB & IS4 middle tier.
Secondly, that sample is about 4 years old, and IS4 V3 has changed a lot.
Thanks
This is great. Would love to see this expanded with jwt tokens (including refresh) + CosmosDB backend.
Hello Malcolm. Thank you for the comment. We are about to release our book with bonuses and inside the book we have an example with Web API + Identity + Jwt + SqlDb (yeah I know it’s not Cosmos 😀 ). If you would like to have it, we started today an offer for our subscribers (the best one). So if you are subscriber, you received an email, if not, just subscribe 😀 Anhow, thank you a lot for reading and commenting. Best wishes.