Hi, today we will learn how to use asp.net core identity to make an authentication system and use permission/claim based authorization to secure asp.net web application. About permission, let me explain. For example, there is a module Blog . So, for Blog module there can be 4types of permissions. Blog.View, Blog.Create, Blog.Edit, Blog.Delete . When a user tries to view a blog post, the user must have Blog.View permission. When tries to create post, the user must have Blog.Create permission. Using this approach to authorize users are very reliable, scalable and maintable. Lets learn then.

Open visual studio and create new MVC(model-view-controller) project. Lets name the project “Identity” and select target framework .NET 5. Look below picture if you find it difficult to understand.

Create the project. Once visual studio prepared the project you will see the project structure like this .

Lets install following nuget packages from Package Manager Console. Make sure SqlServer is installed on your machine.
Install-Package Microsoft.AspNetCore.Identity.EntityFrameworkCore -Version 5.0.0 Install-Package Microsoft.EntityFrameworkCore.SqlServer -Version 5.0.0 Install-Package Microsoft.EntityFrameworkCore.Tools -Version 5.0.0
Create a class in Models folder and name it AppUser. Write following code there.
using Microsoft.AspNetCore.Identity; namespace Identity.Models { public class AppUser : IdentityUser { public string FirstName { get; set; } public string LastName { get; set; } } }
Create another class in same folder and name it AppRole and paste the following code.
using Microsoft.AspNetCore.Identity; namespace Identity.Models { public class AppRole : IdentityRole { public AppRole(string name) : base(name) { } public string Description { get; set; } } }
Above two class are user model and role model. We will map them to DbContext so that EntityFramework can pick them and work as entities. Under Identity, create a folder and name it Data. Inside this folder create a class and name it IdentityContext. Paste the following code into it.
using Identity.Models; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; namespace Identity.Data { public sealed class IdentityContext : IdentityDbContext<AppUser, AppRole, string> { public IdentityContext(DbContextOptions<IdentityContext> options) : base(options) { } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.Entity<AppUser>(entity => entity.Property(m => m.Id).HasMaxLength(85)); modelBuilder.Entity<AppUser>(entity => entity.Property(m => m.NormalizedEmail).HasMaxLength(85)); modelBuilder.Entity<AppUser>(entity => entity.Property(m => m.NormalizedUserName).HasMaxLength(85)); modelBuilder.Entity<AppRole>(entity => entity.Property(m => m.Id).HasMaxLength(85)); modelBuilder.Entity<AppRole>(entity => entity.Property(m => m.NormalizedName).HasMaxLength(85)); modelBuilder.Entity<IdentityUserLogin<string>>(entity => entity.Property(m => m.LoginProvider).HasMaxLength(85)); modelBuilder.Entity<IdentityUserLogin<string>>(entity => entity.Property(m => m.ProviderKey).HasMaxLength(85)); modelBuilder.Entity<IdentityUserLogin<string>>(entity => entity.Property(m => m.UserId).HasMaxLength(85)); modelBuilder.Entity<IdentityUserRole<string>>(entity => entity.Property(m => m.UserId).HasMaxLength(85)); modelBuilder.Entity<IdentityUserRole<string>>(entity => entity.Property(m => m.RoleId).HasMaxLength(85)); modelBuilder.Entity<IdentityUserToken<string>>(entity => entity.Property(m => m.UserId).HasMaxLength(85)); modelBuilder.Entity<IdentityUserToken<string>>(entity => entity.Property(m => m.LoginProvider).HasMaxLength(85)); modelBuilder.Entity<IdentityUserToken<string>>(entity => entity.Property(m => m.Name).HasMaxLength(85)); modelBuilder.Entity<IdentityUserClaim<string>>(entity => entity.Property(m => m.Id).HasMaxLength(85)); modelBuilder.Entity<IdentityUserClaim<string>>(entity => entity.Property(m => m.UserId).HasMaxLength(85)); modelBuilder.Entity<IdentityRoleClaim<string>>(entity => entity.Property(m => m.Id).HasMaxLength(85)); modelBuilder.Entity<IdentityRoleClaim<string>>(entity => entity.Property(m => m.RoleId).HasMaxLength(85)); modelBuilder.Entity<AppUser>(entity => { entity.ToTable(name: "Users"); }); modelBuilder.Entity<AppRole>(entity => { entity.ToTable(name: "Roles"); }); modelBuilder.Entity<IdentityUserRole<string>>(entity => { entity.ToTable("UserRoles"); }); modelBuilder.Entity<IdentityUserClaim<string>>(entity => { entity.ToTable("UserClaims"); }); modelBuilder.Entity<IdentityUserLogin<string>>(entity => { entity.ToTable("UserLogins"); }); modelBuilder.Entity<IdentityRoleClaim<string>>(entity => { entity.ToTable("RoleClaims"); }); modelBuilder.Entity<IdentityUserToken<string>>(entity => { entity.ToTable("UserTokens"); }); } } }
The DbContext class is bridge between AppUser, AppRole models and Database. Append following content on top of appsettings.json .
"ConnectionStrings": { "IdentityConnection": "Server=(localdb)\\mssqllocaldb;Database=Identity;Integrated Security=true" },
Lets configure Identity and EntityFramework to work with this connectionstring. Open Startup.cs and inside ConfigureServices(IServiceCollection services) method add the following content.
services.AddDbContext<IdentityContext>(options => options.UseSqlServer(Configuration.GetConnectionString("IdentityConnection"), b => b.MigrationsAssembly(typeof(IdentityContext).Assembly.FullName))); services.AddIdentity<AppUser, AppRole>(options => { options.Password.RequireDigit = false; options.Password.RequireNonAlphanumeric = false; options.Password.RequireUppercase = false; options.Password.RequiredLength = 4; } ).AddEntityFrameworkStores<IdentityContext>() .AddDefaultTokenProviders();
Add following line in Configure method just before app.UseAuthorization()
app.UseAuthentication();
Now the startup class should look like this.
using Identity.Data; using Identity.Models; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; namespace Identity { public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddDbContext<IdentityContext>(options => options.UseSqlServer(Configuration.GetConnectionString("IdentityConnection"), b => b.MigrationsAssembly(typeof(IdentityContext).Assembly.FullName))); services.AddIdentity<AppUser, AppRole>(options => { options.Password.RequireDigit = false; options.Password.RequireNonAlphanumeric = false; options.Password.RequireUppercase = false; options.Password.RequiredLength = 4; } ).AddEntityFrameworkStores<IdentityContext>() .AddDefaultTokenProviders(); services.AddControllersWithViews(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); }); } } }
Lets add initial migration and create required database and tables as defined above. Open Pacakge Manager Console and hit following commands.
Add-Migration Initial -Context IdentityContext -Verbose Update-Database -Context IdentityContext -Verbose
Now if you check your sqlserver, you should see Identiy database and related tables like following picture.

Core configuration is done for entityframework and identity. Above concepts are almost same however you use identity and entityFramework. Source Code of works till now can be found here. Now we need to design our razor pages and backend functionalities to handle user login, register, authorization. The implementation logic varies based on requirement and persons. I will implement a simple login, registration and show how authentication is working in next chapter. Once authentication is done we will move to permission based authorizations.
Read the next from here.