1) Hvad er idéen?
ASP.NET Core Identity er Microsofts login-system til .NET. Det kan håndtere brugere, passwords, roller, claims, password hashing og login-flow.
Normalt kan Identity-tabellerne ligge i samme database som resten af projektet. Men i større projekter kan det være mere ryddeligt at splitte det op.
AuthDbbruges til Identity-tabeller som brugere, roller og login.ProjectDbbruges til projektets egne data, for eksempel produkter, opgaver, noter eller scanninger.
Fordelen er, at authentication og projektdata ikke bliver blandet sammen. Det gør projektet nemmere at forstå og nemmere at vedligeholde.
2) Installer pakker
Først installerer vi de NuGet-pakker, som projektet skal bruge. EF Core bruges til databaserne, Identity bruges til brugere, og JWT bruges til token-baseret login i API'et.
bash · 4 lines
1dotnet add package Microsoft.EntityFrameworkCore.SqlServer2dotnet add package Microsoft.EntityFrameworkCore.Design3dotnet add package Microsoft.AspNetCore.Identity.EntityFrameworkCore4dotnet add package Microsoft.AspNetCore.Authentication.JwtBearerHvad bruges pakkerne til?
Microsoft.EntityFrameworkCore.SqlServerforbinder EF Core til SQL Server.Microsoft.EntityFrameworkCore.Designbruges når vi laver migrations fra terminalen.Microsoft.AspNetCore.Identity.EntityFrameworkCoregør at Identity kan gemme brugere via EF Core.Microsoft.AspNetCore.Authentication.JwtBearergør at API'et kan validere JWT tokens.
3) Connection strings
Nu opretter vi to connection strings. Det er her vi fortæller appen, hvor databaserne ligger.
Det vigtige er, at AuthConnection og ProjectConnection peger på hver sin database.
json · 12 lines
1{2 "ConnectionStrings": {3 "AuthConnection": "Server=localhost;Database=AuthDb;Trusted_Connection=True;TrustServerCertificate=True;",4 "ProjectConnection": "Server=localhost;Database=ProjectDb;Trusted_Connection=True;TrustServerCertificate=True;"5 },6 7 "Jwt": {8 "Key": "THIS_IS_A_LONG_SECRET_KEY_FOR_DEVELOPMENT_ONLY",9 "Issuer": "MyApi",10 "Audience": "MyApiUsers"11 }12}Husk
AuthConnectionbruges afAuthDbContext.ProjectConnectionbruges afProjectDbContext.Jwt:Keyskal være længere og mere sikker i et rigtigt projekt.
4) ApplicationUser
Identity har allerede en standard brugerklasse, som hedder IdentityUser. Den indeholder felter som id, email, username, password hash og security stamp.
Hvis vi vil gemme ekstra information på brugeren, laver vi vores egen klasse, der arver fra IdentityUser.
csharp · 8 lines
1using Microsoft.AspNetCore.Identity;2 3namespace MyApi.Models.Auth;4 5public class ApplicationUser : IdentityUser6{7 public string DisplayName { get; set; } = "";8}Her tilføjer vi kun DisplayName, men du kan senere tilføje flere felter, hvis projektet har brug for det.
5) AuthDbContext
AuthDbContext er den database-context, som kun skal bruges til Identity.
Derfor arver den fra IdentityDbContext<ApplicationUser> i stedet for almindelig DbContext.
csharp · 13 lines
1using Microsoft.AspNetCore.Identity.EntityFrameworkCore;2using Microsoft.EntityFrameworkCore;3using MyApi.Models.Auth;4 5namespace MyApi.Data;6 7public class AuthDbContext : IdentityDbContext<ApplicationUser>8{9 public AuthDbContext(DbContextOptions<AuthDbContext> options)10 : base(options)11 {12 }13}Når vi laver migration for denne context, laver EF Core Identity-tabeller som AspNetUsers, AspNetRoles og AspNetUserRoles.
6) ProjectDbContext
ProjectDbContext er projektets normale database. Det er her dine egne modeller skal ligge.
I dette eksempel bruger vi bare en simpel Product model, så guiden er nem at genbruge.
csharp · 7 lines
1namespace MyApi.Models.Project;2 3public class Product4{5 public int Id { get; set; }6 public string Name { get; set; } = "";7}csharp · 14 lines
1using Microsoft.EntityFrameworkCore;2using MyApi.Models.Project;3 4namespace MyApi.Data;5 6public class ProjectDbContext : DbContext7{8 public ProjectDbContext(DbContextOptions<ProjectDbContext> options)9 : base(options)10 {11 }12 13 public DbSet<Product> Products => Set<Product>();14}Senere kan du udskifte Product med dine egne modeller, for eksempel Scan, Recipeeller Note.
7) Program.cs
I Program.cs samler vi hele opsætningen. Her registrerer vi begge databaser, Identity og JWT authentication.
csharp · 64 lines
1using System.Text;2using Microsoft.AspNetCore.Authentication.JwtBearer;3using Microsoft.AspNetCore.Identity;4using Microsoft.EntityFrameworkCore;5using Microsoft.IdentityModel.Tokens;6using MyApi.Data;7using MyApi.Models.Auth;8 9var builder = WebApplication.CreateBuilder(args);10 11builder.Services.AddControllers();12 13builder.Services.AddDbContext<AuthDbContext>(options =>14{15 options.UseSqlServer(16 builder.Configuration.GetConnectionString("AuthConnection"));17});18 19builder.Services.AddDbContext<ProjectDbContext>(options =>20{21 options.UseSqlServer(22 builder.Configuration.GetConnectionString("ProjectConnection"));23});24 25builder.Services26 .AddIdentity<ApplicationUser, IdentityRole>()27 .AddEntityFrameworkStores<AuthDbContext>()28 .AddDefaultTokenProviders();29 30var jwtKey = builder.Configuration["Jwt:Key"] ?? "";31var keyBytes = Encoding.UTF8.GetBytes(jwtKey);32 33builder.Services34 .AddAuthentication(options =>35 {36 options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;37 options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;38 })39 .AddJwtBearer(options =>40 {41 options.TokenValidationParameters = new TokenValidationParameters42 {43 ValidateIssuer = true,44 ValidateAudience = true,45 ValidateIssuerSigningKey = true,46 ValidateLifetime = true,47 ValidIssuer = builder.Configuration["Jwt:Issuer"],48 ValidAudience = builder.Configuration["Jwt:Audience"],49 IssuerSigningKey = new SymmetricSecurityKey(keyBytes)50 };51 });52 53builder.Services.AddAuthorization();54 55var app = builder.Build();56 57app.UseHttpsRedirection();58 59app.UseAuthentication();60app.UseAuthorization();61 62app.MapControllers();63 64app.Run();Hvad sker der i Program.cs?
AddDbContext<AuthDbContext>kobler Identity-databasen på.AddDbContext<ProjectDbContext>kobler projektets database på.AddIdentityaktiverer ASP.NET Core Identity.AddEntityFrameworkStores<AuthDbContext>fortæller Identity, at brugere skal gemmes iAuthDbContext.AddAuthenticationogAddJwtBearergør API'et klar til JWT login.UseAuthenticationskal stå førUseAuthorization.
8) Lav migrations til hver database
Fordi projektet har to DbContext klasser, skal EF Core vide, hvilken database migrationen skal laves til.
Derfor bruger vi --context, når vi laver og kører migrations.
bash · 7 lines
1dotnet ef migrations add InitAuthDb --context AuthDbContext --output-dir Migrations/AuthDb2 3dotnet ef migrations add InitProjectDb --context ProjectDbContext --output-dir Migrations/ProjectDb4 5dotnet ef database update --context AuthDbContext6 7dotnet ef database update --context ProjectDbContextTypisk fejl
Hvis du glemmer --context, kan EF Core blive i tvivl om hvilken database den skal bruge.
9) Beskyt en controller med login
Når JWT authentication er sat op, kan vi beskytte endpoints med [Authorize].
I eksemplet bruger controlleren ProjectDbContext, fordi products hører til projektets data — ikke Identity-databasen.
csharp · 26 lines
1using Microsoft.AspNetCore.Authorization;2using Microsoft.AspNetCore.Mvc;3using Microsoft.EntityFrameworkCore;4using MyApi.Data;5using MyApi.Models.Project;6 7namespace MyApi.Controllers;8 9[ApiController]10[Route("api/[controller]")]11[Authorize]12public class ProductsController : ControllerBase13{14 private readonly ProjectDbContext db;15 16 public ProductsController(ProjectDbContext db)17 {18 this.db = db;19 }20 21 [HttpGet]22 public async Task<ActionResult<List<Product>>> GetProducts()23 {24 return await db.Products.ToListAsync();25 }26}10) Mental model
Den nemmeste måde at tænke på strukturen er sådan her:
- Login, brugere og roller går gennem
AuthDbContext. - Appens egne data går gennem
ProjectDbContext. - Controllers vælger den context, de har brug for.
- Migrations køres separat for hver context.
11) Kort opsummering
AuthDbContextstyrer Identity-tabeller.ProjectDbContextstyrer projektets egne tabeller.- Begge contexts får hver sin connection string.
- Identity bruger
AddEntityFrameworkStores<AuthDbContext>. - Migrations skal køres med
--context.