Identity 身份认证和授权终结点

This commit is contained in:
hello 2024-03-07 20:10:52 +08:00
parent 2f79bf6b25
commit e7cbd32a39
22 changed files with 1087 additions and 167 deletions

View File

@ -0,0 +1,34 @@
// Copyright (c) HelloShop Corporation. All rights reserved.
// See the license file in the project root for more information.
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace HelloShop.IdentityService.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class TestsController : ControllerBase
{
[HttpGet(nameof(Foo))]
[Authorize(Roles = "AdminRole")]
public IActionResult Foo()
{
return Ok("Hello, World!");
}
[HttpGet(nameof(Bar))]
[Authorize(Roles = "GuestRole")]
public IActionResult Bar()
{
return Ok("Hello, World!");
}
[HttpGet(nameof(Baz))]
public IActionResult Baz()
{
return Ok("Hello, World!");
}
}
}

View File

@ -27,8 +27,6 @@ namespace HelloShop.IdentityService.Controllers
[HttpPost]
public void Post([FromBody] User value)
{
value.CreationTime = DateTimeOffset.Now;
dbContext.Add(value);
dbContext.SaveChanges();
}

View File

@ -1,27 +0,0 @@
using HelloShop.IdentityService.Entities;
using HelloShop.IdentityService.EntityFrameworks;
using HelloShop.ServiceDefaults.Infrastructure;
namespace HelloShop.IdentityService.DataSeeding
{
public class User2DataSeedingProvider : IDataSeedingProvider
{
public async Task SeedingAsync(IServiceProvider serviceProvider)
{
var dbContext = serviceProvider.GetRequiredService<IdentityServiceDbContext>();
var guestUser = dbContext.Set<User>().SingleOrDefault(x => x.UserName == "guest2");
if (guestUser is null)
{
await dbContext.Set<User>().AddAsync(new User
{
UserName = "guest2",
PasswordHash = "AQAAAAEAACcQAAAAEJ"
});
await dbContext.SaveChangesAsync();
}
}
}
}

View File

@ -1,24 +1,64 @@
using HelloShop.IdentityService.Entities;
using HelloShop.IdentityService.EntityFrameworks;
using HelloShop.ServiceDefaults.Infrastructure;
using Microsoft.AspNetCore.Identity;
namespace HelloShop.IdentityService.DataSeeding
{
public class UserDataSeedingProvider(IdentityServiceDbContext dbContext) : IDataSeedingProvider
public class UserDataSeedingProvider(UserManager<User> userManager, RoleManager<Role> roleManager) : IDataSeedingProvider
{
public async Task SeedingAsync(IServiceProvider serviceProvider)
{
var guestUser = dbContext.Set<User>().SingleOrDefault(x => x.UserName == "guest");
var adminRole = await roleManager.FindByNameAsync("AdminRole");
if (guestUser is null)
if (adminRole == null)
{
await dbContext.Set<User>().AddAsync(new User
await roleManager.CreateAsync(new Role
{
Name = "AdminRole"
});
}
var guestRole = await roleManager.FindByNameAsync("GuestRole");
if (guestRole == null)
{
await roleManager.CreateAsync(new Role
{
Name = "GuestRole"
});
}
var adminUser = await userManager.FindByNameAsync("admin");
if (adminUser == null)
{
await userManager.CreateAsync(new User
{
UserName = "admin",
Email = "admin@test.com"
},"admin");
}
if (adminUser!=null)
{
await userManager.AddToRolesAsync(adminUser, ["AdminRole", "GuestRole"]);
}
var guestUser = await userManager.FindByNameAsync("guest");
if (guestUser == null)
{
await userManager.CreateAsync(new User
{
UserName = "guest",
PasswordHash = "AQAAAAEAACcQAAAAEJ"
});
Email = "guest@test.com"
},"guest");
}
await dbContext.SaveChangesAsync();
if (guestUser!=null)
{
await userManager.AddToRoleAsync(guestUser, "GuestRole");
}
}
}

View File

@ -0,0 +1,12 @@
// Copyright (c) HelloShop Corporation. All rights reserved.
// See the license file in the project root for more information.
using Microsoft.AspNetCore.Identity;
namespace HelloShop.IdentityService.Entities
{
public class Role: IdentityRole<int>
{
public DateTimeOffset CreationTime { get; set; }=TimeProvider.System.GetUtcNow();
}
}

View File

@ -1,13 +1,12 @@
namespace HelloShop.IdentityService.Entities
// Copyright (c) HelloShop Corporation. All rights reserved.
// See the license file in the project root for more information.
using Microsoft.AspNetCore.Identity;
namespace HelloShop.IdentityService.Entities
{
public class User
public class User: IdentityUser<int>
{
public int Id { get; set; }
public string UserName { get; set; } = default!;
public string PasswordHash { get; set; } = default!;
public DateTimeOffset CreationTime { get; set; } = DateTimeOffset.UtcNow;
public DateTimeOffset CreationTime { get; init; } = TimeProvider.System.GetUtcNow();
}
}

View File

@ -0,0 +1,19 @@
// Copyright (c) HelloShop Corporation. All rights reserved.
// See the license file in the project root for more information.
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.EntityFrameworkCore;
namespace HelloShop.IdentityService.EntityFrameworks.EntityConfigurations
{
public class RoleClaimEntityTypeConfiguration : IEntityTypeConfiguration<IdentityRoleClaim<int>>
{
public void Configure(EntityTypeBuilder<IdentityRoleClaim<int>> builder)
{
builder.ToTable("RoleClaims");
builder.Property(rc => rc.ClaimType).HasMaxLength(128);
}
}
}

View File

@ -0,0 +1,23 @@
// Copyright (c) HelloShop Corporation. All rights reserved.
// See the license file in the project root for more information.
using HelloShop.IdentityService.Entities;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.EntityFrameworkCore;
namespace HelloShop.IdentityService.EntityFrameworks.EntityConfigurations
{
public class RoleEntityTypeConfiguration : IEntityTypeConfiguration<Role>
{
public void Configure(EntityTypeBuilder<Role> builder)
{
builder.ToTable("Roles");
builder.Property(r => r.Id).HasColumnOrder(1);
builder.Property(r => r.Name).HasMaxLength(16).HasColumnOrder(2);
builder.Property(r => r.NormalizedName).HasMaxLength(16).HasColumnOrder(3);
builder.Property(r => r.ConcurrencyStamp).HasMaxLength(64).HasColumnOrder(4);
builder.Property(r => r.CreationTime).HasColumnOrder(5);
}
}
}

View File

@ -0,0 +1,19 @@
// Copyright (c) HelloShop Corporation. All rights reserved.
// See the license file in the project root for more information.
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.EntityFrameworkCore;
namespace HelloShop.IdentityService.EntityFrameworks.EntityConfigurations
{
public class UserClaimEntityTypeConfiguration : IEntityTypeConfiguration<IdentityUserClaim<int>>
{
public void Configure(EntityTypeBuilder<IdentityUserClaim<int>> builder)
{
builder.ToTable("UserClaims");
builder.Property(uc => uc.ClaimType).HasMaxLength(128);
}
}
}

View File

@ -10,11 +10,22 @@ namespace HelloShop.IdentityService.EntityFrameworks.EntityConfigurations
{
builder.ToTable("Users");
builder.HasKey(u => u.Id);
builder.Property(u => u.Id).HasColumnOrder(1);
builder.Property(u => u.UserName).HasMaxLength(50).HasColumnOrder(3);
builder.Property(u => u.PasswordHash).HasMaxLength(100).HasColumnOrder(2);
builder.Property(u => u.UserName).HasMaxLength(16).HasColumnOrder(2);
builder.Property(u => u.NormalizedUserName).HasMaxLength(16).HasColumnOrder(3);
builder.Property(u => u.Email).HasMaxLength(32).HasColumnOrder(4);
builder.Property(u => u.NormalizedEmail).HasMaxLength(32).HasColumnOrder(5);
builder.Property(u => u.EmailConfirmed).HasColumnOrder(6);
builder.Property(u => u.PasswordHash).HasMaxLength(512).HasColumnOrder(7);
builder.Property(u => u.SecurityStamp).HasMaxLength(32).HasColumnOrder(8);
builder.Property(u => u.ConcurrencyStamp).HasMaxLength(64).HasColumnOrder(9);
builder.Property(u => u.PhoneNumber).HasMaxLength(16).HasColumnOrder(10);
builder.Property(u => u.PhoneNumberConfirmed).HasColumnOrder(11);
builder.Property(u => u.TwoFactorEnabled).HasColumnOrder(12);
builder.Property(u => u.LockoutEnd).HasColumnOrder(13);
builder.Property(u => u.LockoutEnabled).HasColumnOrder(14);
builder.Property(u => u.AccessFailedCount).HasColumnOrder(15);
builder.Property(u => u.CreationTime).HasColumnOrder(16);
}
}
}

View File

@ -0,0 +1,20 @@
// Copyright (c) HelloShop Corporation. All rights reserved.
// See the license file in the project root for more information.
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.EntityFrameworkCore;
namespace HelloShop.IdentityService.EntityFrameworks.EntityConfigurations
{
public class UserLoginEntityTypeConfiguration : IEntityTypeConfiguration<IdentityUserLogin<int>>
{
public void Configure(EntityTypeBuilder<IdentityUserLogin<int>> builder)
{
builder.ToTable("UserLogins");
builder.Property(ul => ul.LoginProvider).HasMaxLength(16);
builder.Property(ul => ul.ProviderDisplayName).HasMaxLength(16);
}
}
}

View File

@ -0,0 +1,16 @@
// Copyright (c) HelloShop Corporation. All rights reserved.
// See the license file in the project root for more information.
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
namespace HelloShop.IdentityService.EntityFrameworks.EntityConfigurations
{
public class UserRoleEntityTypeConfiguration : IEntityTypeConfiguration<IdentityUserRole<int>>
{
public void Configure(Microsoft.EntityFrameworkCore.Metadata.Builders.EntityTypeBuilder<IdentityUserRole<int>> builder)
{
builder.ToTable("UserRoles");
}
}
}

View File

@ -0,0 +1,20 @@
// Copyright (c) HelloShop Corporation. All rights reserved.
// See the license file in the project root for more information.
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.EntityFrameworkCore;
namespace HelloShop.IdentityService.EntityFrameworks.EntityConfigurations
{
public class UserTokenEntityTypeConfiguration : IEntityTypeConfiguration<IdentityUserToken<int>>
{
public void Configure(EntityTypeBuilder<IdentityUserToken<int>> builder)
{
builder.ToTable("UserTokens");
builder.Property(ut => ut.Name).HasMaxLength(16);
builder.Property(ut => ut.LoginProvider).HasMaxLength(16);
}
}
}

View File

@ -1,9 +1,11 @@
using Microsoft.EntityFrameworkCore;
using HelloShop.IdentityService.Entities;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using System.Reflection;
namespace HelloShop.IdentityService.EntityFrameworks
{
public class IdentityServiceDbContext(DbContextOptions<IdentityServiceDbContext> options) : DbContext(options)
public class IdentityServiceDbContext(DbContextOptions<IdentityServiceDbContext> options) : IdentityDbContext<User, Role, int>(options)
{
protected override void OnModelCreating(ModelBuilder modelBuilder)
{

View File

@ -1,59 +0,0 @@
// <auto-generated />
using System;
using HelloShop.IdentityService.EntityFrameworks;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace HelloShop.IdentityService.EntityFrameworks.Migrations
{
[DbContext(typeof(IdentityServiceDbContext))]
[Migration("20240302004354_InitialCreate")]
partial class InitialCreate
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.2")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("HelloShop.IdentityService.Entities.User", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnOrder(1);
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<DateTimeOffset>("CreationTime")
.HasColumnType("timestamp with time zone");
b.Property<string>("PasswordHash")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("character varying(100)")
.HasColumnOrder(2);
b.Property<string>("UserName")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("character varying(50)")
.HasColumnOrder(3);
b.HasKey("Id");
b.ToTable("Users", (string)null);
});
#pragma warning restore 612, 618
}
}
}

View File

@ -1,38 +0,0 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace HelloShop.IdentityService.EntityFrameworks.Migrations
{
/// <inheritdoc />
public partial class InitialCreate : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Users",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
PasswordHash = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: false),
UserName = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: false),
CreationTime = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Users", x => x.Id);
});
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Users");
}
}
}

View File

@ -0,0 +1,318 @@
// <auto-generated />
using System;
using HelloShop.IdentityService.EntityFrameworks;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace HelloShop.IdentityService.EntityFrameworks.Migrations
{
[DbContext(typeof(IdentityServiceDbContext))]
[Migration("20240307112633_InitialCreate")]
partial class InitialCreate
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.2")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("HelloShop.IdentityService.Entities.Role", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnOrder(1);
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasMaxLength(64)
.HasColumnType("character varying(64)")
.HasColumnOrder(4);
b.Property<DateTimeOffset>("CreationTime")
.HasColumnType("timestamp with time zone")
.HasColumnOrder(5);
b.Property<string>("Name")
.HasMaxLength(16)
.HasColumnType("character varying(16)")
.HasColumnOrder(2);
b.Property<string>("NormalizedName")
.HasMaxLength(16)
.HasColumnType("character varying(16)")
.HasColumnOrder(3);
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("Roles", (string)null);
});
modelBuilder.Entity("HelloShop.IdentityService.Entities.User", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnOrder(1);
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("AccessFailedCount")
.HasColumnType("integer")
.HasColumnOrder(15);
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasMaxLength(64)
.HasColumnType("character varying(64)")
.HasColumnOrder(9);
b.Property<DateTimeOffset>("CreationTime")
.HasColumnType("timestamp with time zone")
.HasColumnOrder(16);
b.Property<string>("Email")
.HasMaxLength(32)
.HasColumnType("character varying(32)")
.HasColumnOrder(4);
b.Property<bool>("EmailConfirmed")
.HasColumnType("boolean")
.HasColumnOrder(6);
b.Property<bool>("LockoutEnabled")
.HasColumnType("boolean")
.HasColumnOrder(14);
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("timestamp with time zone")
.HasColumnOrder(13);
b.Property<string>("NormalizedEmail")
.HasMaxLength(32)
.HasColumnType("character varying(32)")
.HasColumnOrder(5);
b.Property<string>("NormalizedUserName")
.HasMaxLength(16)
.HasColumnType("character varying(16)")
.HasColumnOrder(3);
b.Property<string>("PasswordHash")
.HasMaxLength(512)
.HasColumnType("character varying(512)")
.HasColumnOrder(7);
b.Property<string>("PhoneNumber")
.HasMaxLength(16)
.HasColumnType("character varying(16)")
.HasColumnOrder(10);
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("boolean")
.HasColumnOrder(11);
b.Property<string>("SecurityStamp")
.HasMaxLength(32)
.HasColumnType("character varying(32)")
.HasColumnOrder(8);
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("boolean")
.HasColumnOrder(12);
b.Property<string>("UserName")
.HasMaxLength(16)
.HasColumnType("character varying(16)")
.HasColumnOrder(2);
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasDatabaseName("UserNameIndex");
b.ToTable("Users", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<int>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<string>("ClaimValue")
.HasColumnType("text");
b.Property<int>("RoleId")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("RoleClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<int>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<string>("ClaimValue")
.HasColumnType("text");
b.Property<int>("UserId")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("UserClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<int>", b =>
{
b.Property<string>("LoginProvider")
.HasMaxLength(16)
.HasColumnType("character varying(16)");
b.Property<string>("ProviderKey")
.HasColumnType("text");
b.Property<string>("ProviderDisplayName")
.HasMaxLength(16)
.HasColumnType("character varying(16)");
b.Property<int>("UserId")
.HasColumnType("integer");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("UserLogins", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<int>", b =>
{
b.Property<int>("UserId")
.HasColumnType("integer");
b.Property<int>("RoleId")
.HasColumnType("integer");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("UserRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<int>", b =>
{
b.Property<int>("UserId")
.HasColumnType("integer");
b.Property<string>("LoginProvider")
.HasMaxLength(16)
.HasColumnType("character varying(16)");
b.Property<string>("Name")
.HasMaxLength(16)
.HasColumnType("character varying(16)");
b.Property<string>("Value")
.HasColumnType("text");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("UserTokens", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<int>", b =>
{
b.HasOne("HelloShop.IdentityService.Entities.Role", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<int>", b =>
{
b.HasOne("HelloShop.IdentityService.Entities.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<int>", b =>
{
b.HasOne("HelloShop.IdentityService.Entities.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<int>", b =>
{
b.HasOne("HelloShop.IdentityService.Entities.Role", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("HelloShop.IdentityService.Entities.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<int>", b =>
{
b.HasOne("HelloShop.IdentityService.Entities.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,227 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace HelloShop.IdentityService.EntityFrameworks.Migrations
{
/// <inheritdoc />
public partial class InitialCreate : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Roles",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Name = table.Column<string>(type: "character varying(16)", maxLength: 16, nullable: true),
NormalizedName = table.Column<string>(type: "character varying(16)", maxLength: 16, nullable: true),
ConcurrencyStamp = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: true),
CreationTime = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Roles", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Users",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
UserName = table.Column<string>(type: "character varying(16)", maxLength: 16, nullable: true),
NormalizedUserName = table.Column<string>(type: "character varying(16)", maxLength: 16, nullable: true),
Email = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: true),
NormalizedEmail = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: true),
EmailConfirmed = table.Column<bool>(type: "boolean", nullable: false),
PasswordHash = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: true),
SecurityStamp = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: true),
ConcurrencyStamp = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: true),
PhoneNumber = table.Column<string>(type: "character varying(16)", maxLength: 16, nullable: true),
PhoneNumberConfirmed = table.Column<bool>(type: "boolean", nullable: false),
TwoFactorEnabled = table.Column<bool>(type: "boolean", nullable: false),
LockoutEnd = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
LockoutEnabled = table.Column<bool>(type: "boolean", nullable: false),
AccessFailedCount = table.Column<int>(type: "integer", nullable: false),
CreationTime = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Users", x => x.Id);
});
migrationBuilder.CreateTable(
name: "RoleClaims",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
RoleId = table.Column<int>(type: "integer", nullable: false),
ClaimType = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: true),
ClaimValue = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_RoleClaims", x => x.Id);
table.ForeignKey(
name: "FK_RoleClaims_Roles_RoleId",
column: x => x.RoleId,
principalTable: "Roles",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "UserClaims",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
UserId = table.Column<int>(type: "integer", nullable: false),
ClaimType = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: true),
ClaimValue = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_UserClaims", x => x.Id);
table.ForeignKey(
name: "FK_UserClaims_Users_UserId",
column: x => x.UserId,
principalTable: "Users",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "UserLogins",
columns: table => new
{
LoginProvider = table.Column<string>(type: "character varying(16)", maxLength: 16, nullable: false),
ProviderKey = table.Column<string>(type: "text", nullable: false),
ProviderDisplayName = table.Column<string>(type: "character varying(16)", maxLength: 16, nullable: true),
UserId = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_UserLogins", x => new { x.LoginProvider, x.ProviderKey });
table.ForeignKey(
name: "FK_UserLogins_Users_UserId",
column: x => x.UserId,
principalTable: "Users",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "UserRoles",
columns: table => new
{
UserId = table.Column<int>(type: "integer", nullable: false),
RoleId = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_UserRoles", x => new { x.UserId, x.RoleId });
table.ForeignKey(
name: "FK_UserRoles_Roles_RoleId",
column: x => x.RoleId,
principalTable: "Roles",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_UserRoles_Users_UserId",
column: x => x.UserId,
principalTable: "Users",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "UserTokens",
columns: table => new
{
UserId = table.Column<int>(type: "integer", nullable: false),
LoginProvider = table.Column<string>(type: "character varying(16)", maxLength: 16, nullable: false),
Name = table.Column<string>(type: "character varying(16)", maxLength: 16, nullable: false),
Value = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_UserTokens", x => new { x.UserId, x.LoginProvider, x.Name });
table.ForeignKey(
name: "FK_UserTokens_Users_UserId",
column: x => x.UserId,
principalTable: "Users",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_RoleClaims_RoleId",
table: "RoleClaims",
column: "RoleId");
migrationBuilder.CreateIndex(
name: "RoleNameIndex",
table: "Roles",
column: "NormalizedName",
unique: true);
migrationBuilder.CreateIndex(
name: "IX_UserClaims_UserId",
table: "UserClaims",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_UserLogins_UserId",
table: "UserLogins",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_UserRoles_RoleId",
table: "UserRoles",
column: "RoleId");
migrationBuilder.CreateIndex(
name: "EmailIndex",
table: "Users",
column: "NormalizedEmail");
migrationBuilder.CreateIndex(
name: "UserNameIndex",
table: "Users",
column: "NormalizedUserName",
unique: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "RoleClaims");
migrationBuilder.DropTable(
name: "UserClaims");
migrationBuilder.DropTable(
name: "UserLogins");
migrationBuilder.DropTable(
name: "UserRoles");
migrationBuilder.DropTable(
name: "UserTokens");
migrationBuilder.DropTable(
name: "Roles");
migrationBuilder.DropTable(
name: "Users");
}
}
}

View File

@ -22,6 +22,44 @@ namespace HelloShop.IdentityService.EntityFrameworks.Migrations
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("HelloShop.IdentityService.Entities.Role", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnOrder(1);
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasMaxLength(64)
.HasColumnType("character varying(64)")
.HasColumnOrder(4);
b.Property<DateTimeOffset>("CreationTime")
.HasColumnType("timestamp with time zone")
.HasColumnOrder(5);
b.Property<string>("Name")
.HasMaxLength(16)
.HasColumnType("character varying(16)")
.HasColumnOrder(2);
b.Property<string>("NormalizedName")
.HasMaxLength(16)
.HasColumnType("character varying(16)")
.HasColumnOrder(3);
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("Roles", (string)null);
});
modelBuilder.Entity("HelloShop.IdentityService.Entities.User", b =>
{
b.Property<int>("Id")
@ -31,25 +69,246 @@ namespace HelloShop.IdentityService.EntityFrameworks.Migrations
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("AccessFailedCount")
.HasColumnType("integer")
.HasColumnOrder(15);
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasMaxLength(64)
.HasColumnType("character varying(64)")
.HasColumnOrder(9);
b.Property<DateTimeOffset>("CreationTime")
.HasColumnType("timestamp with time zone");
.HasColumnType("timestamp with time zone")
.HasColumnOrder(16);
b.Property<string>("Email")
.HasMaxLength(32)
.HasColumnType("character varying(32)")
.HasColumnOrder(4);
b.Property<bool>("EmailConfirmed")
.HasColumnType("boolean")
.HasColumnOrder(6);
b.Property<bool>("LockoutEnabled")
.HasColumnType("boolean")
.HasColumnOrder(14);
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("timestamp with time zone")
.HasColumnOrder(13);
b.Property<string>("NormalizedEmail")
.HasMaxLength(32)
.HasColumnType("character varying(32)")
.HasColumnOrder(5);
b.Property<string>("NormalizedUserName")
.HasMaxLength(16)
.HasColumnType("character varying(16)")
.HasColumnOrder(3);
b.Property<string>("PasswordHash")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("character varying(100)")
.HasColumnOrder(2);
.HasMaxLength(512)
.HasColumnType("character varying(512)")
.HasColumnOrder(7);
b.Property<string>("PhoneNumber")
.HasMaxLength(16)
.HasColumnType("character varying(16)")
.HasColumnOrder(10);
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("boolean")
.HasColumnOrder(11);
b.Property<string>("SecurityStamp")
.HasMaxLength(32)
.HasColumnType("character varying(32)")
.HasColumnOrder(8);
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("boolean")
.HasColumnOrder(12);
b.Property<string>("UserName")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("character varying(50)")
.HasColumnOrder(3);
.HasMaxLength(16)
.HasColumnType("character varying(16)")
.HasColumnOrder(2);
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasDatabaseName("UserNameIndex");
b.ToTable("Users", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<int>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<string>("ClaimValue")
.HasColumnType("text");
b.Property<int>("RoleId")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("RoleClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<int>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<string>("ClaimValue")
.HasColumnType("text");
b.Property<int>("UserId")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("UserClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<int>", b =>
{
b.Property<string>("LoginProvider")
.HasMaxLength(16)
.HasColumnType("character varying(16)");
b.Property<string>("ProviderKey")
.HasColumnType("text");
b.Property<string>("ProviderDisplayName")
.HasMaxLength(16)
.HasColumnType("character varying(16)");
b.Property<int>("UserId")
.HasColumnType("integer");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("UserLogins", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<int>", b =>
{
b.Property<int>("UserId")
.HasColumnType("integer");
b.Property<int>("RoleId")
.HasColumnType("integer");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("UserRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<int>", b =>
{
b.Property<int>("UserId")
.HasColumnType("integer");
b.Property<string>("LoginProvider")
.HasMaxLength(16)
.HasColumnType("character varying(16)");
b.Property<string>("Name")
.HasMaxLength(16)
.HasColumnType("character varying(16)");
b.Property<string>("Value")
.HasColumnType("text");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("UserTokens", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<int>", b =>
{
b.HasOne("HelloShop.IdentityService.Entities.Role", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<int>", b =>
{
b.HasOne("HelloShop.IdentityService.Entities.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<int>", b =>
{
b.HasOne("HelloShop.IdentityService.Entities.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<int>", b =>
{
b.HasOne("HelloShop.IdentityService.Entities.Role", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("HelloShop.IdentityService.Entities.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<int>", b =>
{
b.HasOne("HelloShop.IdentityService.Entities.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
#pragma warning restore 612, 618
}
}

View File

@ -6,6 +6,7 @@
<InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>

View File

@ -1,5 +1,6 @@
using HelloShop.IdentityService.Constants;
using HelloShop.IdentityService.DataSeeding;
using HelloShop.IdentityService.Entities;
using HelloShop.IdentityService.EntityFrameworks;
using HelloShop.ServiceDefaults.Extensions;
using Microsoft.EntityFrameworkCore;
@ -11,28 +12,30 @@ builder.AddServiceDefaults();
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddDbContext<IdentityServiceDbContext>(options =>
{
options.UseNpgsql(builder.Configuration.GetConnectionString(DbConstants.ConnectionStringName));
});
builder.Services.AddIdentityApiEndpoints<User>(options =>
{
options.Password.RequireDigit = false;
options.Password.RequireLowercase = false;
options.Password.RequireUppercase = false;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequiredLength = 5;
options.SignIn.RequireConfirmedAccount = false;
}).AddRoles<Role>().AddEntityFrameworkStores<IdentityServiceDbContext>();
builder.Services.AddDataSeedingProviders();
builder.Services.AddOpenApi();
var app = builder.Build();
app.MapDefaultEndpoints();
app.MapGroup("identity").MapIdentityApi<User>();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.MapDefaultEndpoints();
app.UseHttpsRedirection();

View File

@ -3,6 +3,7 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.Swagger;
using Swashbuckle.AspNetCore.SwaggerGen;
using Swashbuckle.AspNetCore.SwaggerUI;
@ -22,6 +23,28 @@ namespace HelloShop.ServiceDefaults.Extensions
services.AddEndpointsApiExplorer();
services.AddSwaggerGen(configureOptions);
services.Configure<SwaggerGenOptions>(options =>
{
options.AddSecurityDefinition("bearerAuth", new OpenApiSecurityScheme
{
Type = SecuritySchemeType.Http,
Scheme = "bearer",
BearerFormat = "JWT",
Description = "JWT Authorization header using the Bearer scheme."
});
options.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "bearerAuth" }
},
Array.Empty<string>()
}
});
});
return services;
}