From d92d51fb3e321da82620efddba757fa9ed681772 Mon Sep 17 00:00:00 2001 From: Sam <315859133@qq.com> Date: Fri, 6 Feb 2026 01:14:11 +0800 Subject: [PATCH] feat: implement OAuth 2.0 login flow with auto-redirect - Modify login page to auto-redirect to auth center - Update auth store to use OAuth login flow - Handle OAuth callback and token exchange - Update logout to use OAuth logout endpoint --- .../20260201153600_InitialCreate.Designer.cs | 312 --------- ...202015716_AddOAuthApplications.Designer.cs | 379 ----------- .../20260202015716_AddOAuthApplications.cs | 53 -- ...0260202031310_AddTenantAndLogs.Designer.cs | 621 ------------------ .../20260202031310_AddTenantAndLogs.cs | 214 ------ .../20260202064650_AddOAuthDescription.cs | 29 - Data/SeedData.cs | 2 +- .../20260205165820_InitialCreate.Designer.cs | 48 +- .../20260205165820_InitialCreate.cs | 188 +++++- .../ApplicationDbContextModelSnapshot.cs | 44 +- 10 files changed, 243 insertions(+), 1647 deletions(-) delete mode 100644 Data/Migrations/20260201153600_InitialCreate.Designer.cs delete mode 100644 Data/Migrations/20260202015716_AddOAuthApplications.Designer.cs delete mode 100644 Data/Migrations/20260202015716_AddOAuthApplications.cs delete mode 100644 Data/Migrations/20260202031310_AddTenantAndLogs.Designer.cs delete mode 100644 Data/Migrations/20260202031310_AddTenantAndLogs.cs delete mode 100644 Data/Migrations/20260202064650_AddOAuthDescription.cs rename Data/Migrations/20260202064650_AddOAuthDescription.Designer.cs => Migrations/20260205165820_InitialCreate.Designer.cs (94%) rename Data/Migrations/20260201153600_InitialCreate.cs => Migrations/20260205165820_InitialCreate.cs (52%) rename {Data/Migrations => Migrations}/ApplicationDbContextModelSnapshot.cs (94%) diff --git a/Data/Migrations/20260201153600_InitialCreate.Designer.cs b/Data/Migrations/20260201153600_InitialCreate.Designer.cs deleted file mode 100644 index 42966cb..0000000 --- a/Data/Migrations/20260201153600_InitialCreate.Designer.cs +++ /dev/null @@ -1,312 +0,0 @@ -// -using System; -using Fengling.AuthService.Data; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace Fengling.AuthService.Data.Migrations -{ - [DbContext(typeof(ApplicationDbContext))] - [Migration("20260201153600_InitialCreate")] - partial class InitialCreate - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.10") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("Fengling.AuthService.Models.ApplicationRole", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("text"); - - b.Property("CreatedTime") - .HasColumnType("timestamp with time zone"); - - b.Property("Description") - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("Name") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("NormalizedName") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedName") - .IsUnique() - .HasDatabaseName("RoleNameIndex"); - - b.ToTable("AspNetRoles", (string)null); - }); - - modelBuilder.Entity("Fengling.AuthService.Models.ApplicationUser", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("AccessFailedCount") - .HasColumnType("integer"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("text"); - - b.Property("CreatedTime") - .HasColumnType("timestamp with time zone"); - - b.Property("Email") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("EmailConfirmed") - .HasColumnType("boolean"); - - b.Property("IsDeleted") - .HasColumnType("boolean"); - - b.Property("LockoutEnabled") - .HasColumnType("boolean"); - - b.Property("LockoutEnd") - .HasColumnType("timestamp with time zone"); - - b.Property("NormalizedEmail") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("NormalizedUserName") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("PasswordHash") - .HasColumnType("text"); - - b.Property("Phone") - .HasMaxLength(20) - .HasColumnType("character varying(20)"); - - b.Property("PhoneNumber") - .HasColumnType("text"); - - b.Property("PhoneNumberConfirmed") - .HasColumnType("boolean"); - - b.Property("RealName") - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("SecurityStamp") - .HasColumnType("text"); - - b.Property("TenantId") - .HasColumnType("bigint"); - - b.Property("TwoFactorEnabled") - .HasColumnType("boolean"); - - b.Property("UpdatedTime") - .HasColumnType("timestamp with time zone"); - - b.Property("UserName") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedEmail") - .HasDatabaseName("EmailIndex"); - - b.HasIndex("NormalizedUserName") - .IsUnique() - .HasDatabaseName("UserNameIndex"); - - b.HasIndex("Phone") - .IsUnique(); - - b.HasIndex("TenantId"); - - b.ToTable("AspNetUsers", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("ClaimType") - .HasColumnType("text"); - - b.Property("ClaimValue") - .HasColumnType("text"); - - b.Property("RoleId") - .HasColumnType("bigint"); - - b.HasKey("Id"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetRoleClaims", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("ClaimType") - .HasColumnType("text"); - - b.Property("ClaimValue") - .HasColumnType("text"); - - b.Property("UserId") - .HasColumnType("bigint"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserClaims", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.Property("LoginProvider") - .HasColumnType("text"); - - b.Property("ProviderKey") - .HasColumnType("text"); - - b.Property("ProviderDisplayName") - .HasColumnType("text"); - - b.Property("UserId") - .HasColumnType("bigint"); - - b.HasKey("LoginProvider", "ProviderKey"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserLogins", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.Property("UserId") - .HasColumnType("bigint"); - - b.Property("RoleId") - .HasColumnType("bigint"); - - b.HasKey("UserId", "RoleId"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetUserRoles", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.Property("UserId") - .HasColumnType("bigint"); - - b.Property("LoginProvider") - .HasColumnType("text"); - - b.Property("Name") - .HasColumnType("text"); - - b.Property("Value") - .HasColumnType("text"); - - b.HasKey("UserId", "LoginProvider", "Name"); - - b.ToTable("AspNetUserTokens", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.HasOne("Fengling.AuthService.Models.ApplicationRole", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.HasOne("Fengling.AuthService.Models.ApplicationUser", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.HasOne("Fengling.AuthService.Models.ApplicationUser", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.HasOne("Fengling.AuthService.Models.ApplicationRole", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Fengling.AuthService.Models.ApplicationUser", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.HasOne("Fengling.AuthService.Models.ApplicationUser", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Data/Migrations/20260202015716_AddOAuthApplications.Designer.cs b/Data/Migrations/20260202015716_AddOAuthApplications.Designer.cs deleted file mode 100644 index 3312d48..0000000 --- a/Data/Migrations/20260202015716_AddOAuthApplications.Designer.cs +++ /dev/null @@ -1,379 +0,0 @@ -// -using System; -using Fengling.AuthService.Data; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace Fengling.AuthService.Data.Migrations -{ - [DbContext(typeof(ApplicationDbContext))] - [Migration("20260202015716_AddOAuthApplications")] - partial class AddOAuthApplications - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "10.0.2") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("Fengling.AuthService.Models.ApplicationRole", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("text"); - - b.Property("CreatedTime") - .HasColumnType("timestamp with time zone"); - - b.Property("Description") - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("Name") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("NormalizedName") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedName") - .IsUnique() - .HasDatabaseName("RoleNameIndex"); - - b.ToTable("AspNetRoles", (string)null); - }); - - modelBuilder.Entity("Fengling.AuthService.Models.ApplicationUser", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("AccessFailedCount") - .HasColumnType("integer"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("text"); - - b.Property("CreatedTime") - .HasColumnType("timestamp with time zone"); - - b.Property("Email") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("EmailConfirmed") - .HasColumnType("boolean"); - - b.Property("IsDeleted") - .HasColumnType("boolean"); - - b.Property("LockoutEnabled") - .HasColumnType("boolean"); - - b.Property("LockoutEnd") - .HasColumnType("timestamp with time zone"); - - b.Property("NormalizedEmail") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("NormalizedUserName") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("PasswordHash") - .HasColumnType("text"); - - b.Property("Phone") - .HasMaxLength(20) - .HasColumnType("character varying(20)"); - - b.Property("PhoneNumber") - .HasColumnType("text"); - - b.Property("PhoneNumberConfirmed") - .HasColumnType("boolean"); - - b.Property("RealName") - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("SecurityStamp") - .HasColumnType("text"); - - b.Property("TenantId") - .HasColumnType("bigint"); - - b.Property("TwoFactorEnabled") - .HasColumnType("boolean"); - - b.Property("UpdatedTime") - .HasColumnType("timestamp with time zone"); - - b.Property("UserName") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedEmail") - .HasDatabaseName("EmailIndex"); - - b.HasIndex("NormalizedUserName") - .IsUnique() - .HasDatabaseName("UserNameIndex"); - - b.HasIndex("Phone") - .IsUnique(); - - b.HasIndex("TenantId"); - - b.ToTable("AspNetUsers", (string)null); - }); - - modelBuilder.Entity("Fengling.AuthService.Models.OAuthApplication", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("ClientId") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("ClientSecret") - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("ClientType") - .IsRequired() - .HasMaxLength(20) - .HasColumnType("character varying(20)"); - - b.Property("ConsentType") - .IsRequired() - .HasMaxLength(20) - .HasColumnType("character varying(20)"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("DisplayName") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.PrimitiveCollection("GrantTypes") - .IsRequired() - .HasColumnType("text[]"); - - b.PrimitiveCollection("PostLogoutRedirectUris") - .IsRequired() - .HasColumnType("text[]"); - - b.PrimitiveCollection("RedirectUris") - .IsRequired() - .HasColumnType("text[]"); - - b.PrimitiveCollection("Scopes") - .IsRequired() - .HasColumnType("text[]"); - - b.Property("Status") - .IsRequired() - .HasMaxLength(20) - .HasColumnType("character varying(20)"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.HasKey("Id"); - - b.HasIndex("ClientId") - .IsUnique(); - - b.ToTable("OAuthApplications"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("ClaimType") - .HasColumnType("text"); - - b.Property("ClaimValue") - .HasColumnType("text"); - - b.Property("RoleId") - .HasColumnType("bigint"); - - b.HasKey("Id"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetRoleClaims", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("ClaimType") - .HasColumnType("text"); - - b.Property("ClaimValue") - .HasColumnType("text"); - - b.Property("UserId") - .HasColumnType("bigint"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserClaims", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.Property("LoginProvider") - .HasColumnType("text"); - - b.Property("ProviderKey") - .HasColumnType("text"); - - b.Property("ProviderDisplayName") - .HasColumnType("text"); - - b.Property("UserId") - .HasColumnType("bigint"); - - b.HasKey("LoginProvider", "ProviderKey"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserLogins", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.Property("UserId") - .HasColumnType("bigint"); - - b.Property("RoleId") - .HasColumnType("bigint"); - - b.HasKey("UserId", "RoleId"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetUserRoles", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.Property("UserId") - .HasColumnType("bigint"); - - b.Property("LoginProvider") - .HasColumnType("text"); - - b.Property("Name") - .HasColumnType("text"); - - b.Property("Value") - .HasColumnType("text"); - - b.HasKey("UserId", "LoginProvider", "Name"); - - b.ToTable("AspNetUserTokens", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.HasOne("Fengling.AuthService.Models.ApplicationRole", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.HasOne("Fengling.AuthService.Models.ApplicationUser", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.HasOne("Fengling.AuthService.Models.ApplicationUser", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.HasOne("Fengling.AuthService.Models.ApplicationRole", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Fengling.AuthService.Models.ApplicationUser", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.HasOne("Fengling.AuthService.Models.ApplicationUser", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Data/Migrations/20260202015716_AddOAuthApplications.cs b/Data/Migrations/20260202015716_AddOAuthApplications.cs deleted file mode 100644 index 7a69abe..0000000 --- a/Data/Migrations/20260202015716_AddOAuthApplications.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace Fengling.AuthService.Data.Migrations -{ - /// - public partial class AddOAuthApplications : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "OAuthApplications", - columns: table => new - { - Id = table.Column(type: "bigint", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - ClientId = table.Column(type: "character varying(100)", maxLength: 100, nullable: false), - ClientSecret = table.Column(type: "character varying(200)", maxLength: 200, nullable: true), - DisplayName = table.Column(type: "character varying(100)", maxLength: 100, nullable: false), - RedirectUris = table.Column(type: "text[]", nullable: false), - PostLogoutRedirectUris = table.Column(type: "text[]", nullable: false), - Scopes = table.Column(type: "text[]", nullable: false), - GrantTypes = table.Column(type: "text[]", nullable: false), - ClientType = table.Column(type: "character varying(20)", maxLength: 20, nullable: false), - ConsentType = table.Column(type: "character varying(20)", maxLength: 20, nullable: false), - Status = table.Column(type: "character varying(20)", maxLength: 20, nullable: false), - CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), - UpdatedAt = table.Column(type: "timestamp with time zone", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_OAuthApplications", x => x.Id); - }); - - migrationBuilder.CreateIndex( - name: "IX_OAuthApplications_ClientId", - table: "OAuthApplications", - column: "ClientId", - unique: true); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "OAuthApplications"); - } - } -} diff --git a/Data/Migrations/20260202031310_AddTenantAndLogs.Designer.cs b/Data/Migrations/20260202031310_AddTenantAndLogs.Designer.cs deleted file mode 100644 index b03ca1a..0000000 --- a/Data/Migrations/20260202031310_AddTenantAndLogs.Designer.cs +++ /dev/null @@ -1,621 +0,0 @@ -// -using System; -using System.Collections.Generic; -using Fengling.AuthService.Data; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace Fengling.AuthService.Data.Migrations -{ - [DbContext(typeof(ApplicationDbContext))] - [Migration("20260202031310_AddTenantAndLogs")] - partial class AddTenantAndLogs - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "10.0.2") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("Fengling.AuthService.Models.AccessLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Action") - .IsRequired() - .HasMaxLength(20) - .HasColumnType("character varying(20)"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Duration") - .HasColumnType("integer"); - - b.Property("ErrorMessage") - .HasColumnType("text"); - - b.Property("IpAddress") - .HasMaxLength(50) - .HasColumnType("character varying(50)"); - - b.Property("Method") - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("RequestData") - .HasColumnType("text"); - - b.Property("Resource") - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("ResponseData") - .HasColumnType("text"); - - b.Property("Status") - .IsRequired() - .HasMaxLength(20) - .HasColumnType("character varying(20)"); - - b.Property("TenantId") - .HasMaxLength(50) - .HasColumnType("character varying(50)"); - - b.Property("UserAgent") - .HasMaxLength(500) - .HasColumnType("character varying(500)"); - - b.Property("UserName") - .HasMaxLength(50) - .HasColumnType("character varying(50)"); - - b.HasKey("Id"); - - b.HasIndex("Action"); - - b.HasIndex("CreatedAt"); - - b.HasIndex("Status"); - - b.HasIndex("TenantId"); - - b.HasIndex("UserName"); - - b.ToTable("AccessLogs"); - }); - - modelBuilder.Entity("Fengling.AuthService.Models.ApplicationRole", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("text"); - - b.Property("CreatedTime") - .HasColumnType("timestamp with time zone"); - - b.Property("Description") - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("DisplayName") - .HasColumnType("text"); - - b.Property("IsSystem") - .HasColumnType("boolean"); - - b.Property("Name") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("NormalizedName") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.PrimitiveCollection>("Permissions") - .HasColumnType("text[]"); - - b.Property("TenantId") - .HasColumnType("bigint"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedName") - .IsUnique() - .HasDatabaseName("RoleNameIndex"); - - b.ToTable("AspNetRoles", (string)null); - }); - - modelBuilder.Entity("Fengling.AuthService.Models.ApplicationUser", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("AccessFailedCount") - .HasColumnType("integer"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("text"); - - b.Property("CreatedTime") - .HasColumnType("timestamp with time zone"); - - b.Property("Email") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("EmailConfirmed") - .HasColumnType("boolean"); - - b.Property("IsDeleted") - .HasColumnType("boolean"); - - b.Property("LockoutEnabled") - .HasColumnType("boolean"); - - b.Property("LockoutEnd") - .HasColumnType("timestamp with time zone"); - - b.Property("NormalizedEmail") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("NormalizedUserName") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("PasswordHash") - .HasColumnType("text"); - - b.Property("Phone") - .HasMaxLength(20) - .HasColumnType("character varying(20)"); - - b.Property("PhoneNumber") - .HasColumnType("text"); - - b.Property("PhoneNumberConfirmed") - .HasColumnType("boolean"); - - b.Property("RealName") - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("SecurityStamp") - .HasColumnType("text"); - - b.Property("TenantId") - .HasColumnType("bigint"); - - b.Property("TwoFactorEnabled") - .HasColumnType("boolean"); - - b.Property("UpdatedTime") - .HasColumnType("timestamp with time zone"); - - b.Property("UserName") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedEmail") - .HasDatabaseName("EmailIndex"); - - b.HasIndex("NormalizedUserName") - .IsUnique() - .HasDatabaseName("UserNameIndex"); - - b.HasIndex("Phone") - .IsUnique(); - - b.HasIndex("TenantId"); - - b.ToTable("AspNetUsers", (string)null); - }); - - modelBuilder.Entity("Fengling.AuthService.Models.AuditLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Action") - .IsRequired() - .HasMaxLength(20) - .HasColumnType("character varying(20)"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Description") - .HasMaxLength(500) - .HasColumnType("character varying(500)"); - - b.Property("ErrorMessage") - .HasColumnType("text"); - - b.Property("IpAddress") - .IsRequired() - .HasMaxLength(50) - .HasColumnType("character varying(50)"); - - b.Property("NewValue") - .HasColumnType("text"); - - b.Property("OldValue") - .HasColumnType("text"); - - b.Property("Operation") - .IsRequired() - .HasMaxLength(20) - .HasColumnType("character varying(20)"); - - b.Property("Operator") - .IsRequired() - .HasMaxLength(50) - .HasColumnType("character varying(50)"); - - b.Property("Status") - .IsRequired() - .HasMaxLength(20) - .HasColumnType("character varying(20)"); - - b.Property("TargetId") - .HasColumnType("bigint"); - - b.Property("TargetName") - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("TargetType") - .HasMaxLength(50) - .HasColumnType("character varying(50)"); - - b.Property("TenantId") - .HasMaxLength(50) - .HasColumnType("character varying(50)"); - - b.HasKey("Id"); - - b.HasIndex("Action"); - - b.HasIndex("CreatedAt"); - - b.HasIndex("Operation"); - - b.HasIndex("Operator"); - - b.HasIndex("TenantId"); - - b.ToTable("AuditLogs"); - }); - - modelBuilder.Entity("Fengling.AuthService.Models.OAuthApplication", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("ClientId") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("ClientSecret") - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("ClientType") - .IsRequired() - .HasMaxLength(20) - .HasColumnType("character varying(20)"); - - b.Property("ConsentType") - .IsRequired() - .HasMaxLength(20) - .HasColumnType("character varying(20)"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("DisplayName") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.PrimitiveCollection("GrantTypes") - .IsRequired() - .HasColumnType("text[]"); - - b.PrimitiveCollection("PostLogoutRedirectUris") - .IsRequired() - .HasColumnType("text[]"); - - b.PrimitiveCollection("RedirectUris") - .IsRequired() - .HasColumnType("text[]"); - - b.PrimitiveCollection("Scopes") - .IsRequired() - .HasColumnType("text[]"); - - b.Property("Status") - .IsRequired() - .HasMaxLength(20) - .HasColumnType("character varying(20)"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.HasKey("Id"); - - b.HasIndex("ClientId") - .IsUnique(); - - b.ToTable("OAuthApplications"); - }); - - modelBuilder.Entity("Fengling.AuthService.Models.Tenant", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("ContactEmail") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("ContactName") - .IsRequired() - .HasMaxLength(50) - .HasColumnType("character varying(50)"); - - b.Property("ContactPhone") - .HasMaxLength(20) - .HasColumnType("character varying(20)"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Description") - .HasMaxLength(500) - .HasColumnType("character varying(500)"); - - b.Property("ExpiresAt") - .HasColumnType("timestamp with time zone"); - - b.Property("IsDeleted") - .HasColumnType("boolean"); - - b.Property("MaxUsers") - .HasColumnType("integer"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("Status") - .IsRequired() - .HasMaxLength(20) - .HasColumnType("character varying(20)"); - - b.Property("TenantId") - .IsRequired() - .HasMaxLength(50) - .HasColumnType("character varying(50)"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.HasKey("Id"); - - b.HasIndex("TenantId") - .IsUnique(); - - b.ToTable("Tenants"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("ClaimType") - .HasColumnType("text"); - - b.Property("ClaimValue") - .HasColumnType("text"); - - b.Property("RoleId") - .HasColumnType("bigint"); - - b.HasKey("Id"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetRoleClaims", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("ClaimType") - .HasColumnType("text"); - - b.Property("ClaimValue") - .HasColumnType("text"); - - b.Property("UserId") - .HasColumnType("bigint"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserClaims", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.Property("LoginProvider") - .HasColumnType("text"); - - b.Property("ProviderKey") - .HasColumnType("text"); - - b.Property("ProviderDisplayName") - .HasColumnType("text"); - - b.Property("UserId") - .HasColumnType("bigint"); - - b.HasKey("LoginProvider", "ProviderKey"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserLogins", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.Property("UserId") - .HasColumnType("bigint"); - - b.Property("RoleId") - .HasColumnType("bigint"); - - b.HasKey("UserId", "RoleId"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetUserRoles", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.Property("UserId") - .HasColumnType("bigint"); - - b.Property("LoginProvider") - .HasColumnType("text"); - - b.Property("Name") - .HasColumnType("text"); - - b.Property("Value") - .HasColumnType("text"); - - b.HasKey("UserId", "LoginProvider", "Name"); - - b.ToTable("AspNetUserTokens", (string)null); - }); - - modelBuilder.Entity("Fengling.AuthService.Models.ApplicationUser", b => - { - b.HasOne("Fengling.AuthService.Models.Tenant", null) - .WithMany("Users") - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.HasOne("Fengling.AuthService.Models.ApplicationRole", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.HasOne("Fengling.AuthService.Models.ApplicationUser", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.HasOne("Fengling.AuthService.Models.ApplicationUser", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.HasOne("Fengling.AuthService.Models.ApplicationRole", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Fengling.AuthService.Models.ApplicationUser", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.HasOne("Fengling.AuthService.Models.ApplicationUser", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Fengling.AuthService.Models.Tenant", b => - { - b.Navigation("Users"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Data/Migrations/20260202031310_AddTenantAndLogs.cs b/Data/Migrations/20260202031310_AddTenantAndLogs.cs deleted file mode 100644 index 5a8aa57..0000000 --- a/Data/Migrations/20260202031310_AddTenantAndLogs.cs +++ /dev/null @@ -1,214 +0,0 @@ -using System; -using System.Collections.Generic; -using Microsoft.EntityFrameworkCore.Migrations; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace Fengling.AuthService.Data.Migrations -{ - /// - public partial class AddTenantAndLogs : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "DisplayName", - table: "AspNetRoles", - type: "text", - nullable: true); - - migrationBuilder.AddColumn( - name: "IsSystem", - table: "AspNetRoles", - type: "boolean", - nullable: false, - defaultValue: false); - - migrationBuilder.AddColumn>( - name: "Permissions", - table: "AspNetRoles", - type: "text[]", - nullable: true); - - migrationBuilder.AddColumn( - name: "TenantId", - table: "AspNetRoles", - type: "bigint", - nullable: true); - - migrationBuilder.CreateTable( - name: "AccessLogs", - columns: table => new - { - Id = table.Column(type: "bigint", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - UserName = table.Column(type: "character varying(50)", maxLength: 50, nullable: true), - TenantId = table.Column(type: "character varying(50)", maxLength: 50, nullable: true), - Action = table.Column(type: "character varying(20)", maxLength: 20, nullable: false), - Resource = table.Column(type: "character varying(200)", maxLength: 200, nullable: true), - Method = table.Column(type: "character varying(10)", maxLength: 10, nullable: true), - IpAddress = table.Column(type: "character varying(50)", maxLength: 50, nullable: true), - UserAgent = table.Column(type: "character varying(500)", maxLength: 500, nullable: true), - Status = table.Column(type: "character varying(20)", maxLength: 20, nullable: false), - Duration = table.Column(type: "integer", nullable: false), - RequestData = table.Column(type: "text", nullable: true), - ResponseData = table.Column(type: "text", nullable: true), - ErrorMessage = table.Column(type: "text", nullable: true), - CreatedAt = table.Column(type: "timestamp with time zone", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_AccessLogs", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "AuditLogs", - columns: table => new - { - Id = table.Column(type: "bigint", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - Operator = table.Column(type: "character varying(50)", maxLength: 50, nullable: false), - TenantId = table.Column(type: "character varying(50)", maxLength: 50, nullable: true), - Operation = table.Column(type: "character varying(20)", maxLength: 20, nullable: false), - Action = table.Column(type: "character varying(20)", maxLength: 20, nullable: false), - TargetType = table.Column(type: "character varying(50)", maxLength: 50, nullable: true), - TargetId = table.Column(type: "bigint", nullable: true), - TargetName = table.Column(type: "character varying(100)", maxLength: 100, nullable: true), - IpAddress = table.Column(type: "character varying(50)", maxLength: 50, nullable: false), - Description = table.Column(type: "character varying(500)", maxLength: 500, nullable: true), - OldValue = table.Column(type: "text", nullable: true), - NewValue = table.Column(type: "text", nullable: true), - ErrorMessage = table.Column(type: "text", nullable: true), - Status = table.Column(type: "character varying(20)", maxLength: 20, nullable: false), - CreatedAt = table.Column(type: "timestamp with time zone", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_AuditLogs", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "Tenants", - columns: table => new - { - Id = table.Column(type: "bigint", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - TenantId = table.Column(type: "character varying(50)", maxLength: 50, nullable: false), - Name = table.Column(type: "character varying(100)", maxLength: 100, nullable: false), - ContactName = table.Column(type: "character varying(50)", maxLength: 50, nullable: false), - ContactEmail = table.Column(type: "character varying(100)", maxLength: 100, nullable: false), - ContactPhone = table.Column(type: "character varying(20)", maxLength: 20, nullable: true), - MaxUsers = table.Column(type: "integer", nullable: true), - CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), - Description = table.Column(type: "character varying(500)", maxLength: 500, nullable: true), - Status = table.Column(type: "character varying(20)", maxLength: 20, nullable: false), - ExpiresAt = table.Column(type: "timestamp with time zone", nullable: true), - UpdatedAt = table.Column(type: "timestamp with time zone", nullable: true), - IsDeleted = table.Column(type: "boolean", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_Tenants", x => x.Id); - }); - - migrationBuilder.CreateIndex( - name: "IX_AccessLogs_Action", - table: "AccessLogs", - column: "Action"); - - migrationBuilder.CreateIndex( - name: "IX_AccessLogs_CreatedAt", - table: "AccessLogs", - column: "CreatedAt"); - - migrationBuilder.CreateIndex( - name: "IX_AccessLogs_Status", - table: "AccessLogs", - column: "Status"); - - migrationBuilder.CreateIndex( - name: "IX_AccessLogs_TenantId", - table: "AccessLogs", - column: "TenantId"); - - migrationBuilder.CreateIndex( - name: "IX_AccessLogs_UserName", - table: "AccessLogs", - column: "UserName"); - - migrationBuilder.CreateIndex( - name: "IX_AuditLogs_Action", - table: "AuditLogs", - column: "Action"); - - migrationBuilder.CreateIndex( - name: "IX_AuditLogs_CreatedAt", - table: "AuditLogs", - column: "CreatedAt"); - - migrationBuilder.CreateIndex( - name: "IX_AuditLogs_Operation", - table: "AuditLogs", - column: "Operation"); - - migrationBuilder.CreateIndex( - name: "IX_AuditLogs_Operator", - table: "AuditLogs", - column: "Operator"); - - migrationBuilder.CreateIndex( - name: "IX_AuditLogs_TenantId", - table: "AuditLogs", - column: "TenantId"); - - migrationBuilder.CreateIndex( - name: "IX_Tenants_TenantId", - table: "Tenants", - column: "TenantId", - unique: true); - - migrationBuilder.AddForeignKey( - name: "FK_AspNetUsers_Tenants_TenantId", - table: "AspNetUsers", - column: "TenantId", - principalTable: "Tenants", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropForeignKey( - name: "FK_AspNetUsers_Tenants_TenantId", - table: "AspNetUsers"); - - migrationBuilder.DropTable( - name: "AccessLogs"); - - migrationBuilder.DropTable( - name: "AuditLogs"); - - migrationBuilder.DropTable( - name: "Tenants"); - - migrationBuilder.DropColumn( - name: "DisplayName", - table: "AspNetRoles"); - - migrationBuilder.DropColumn( - name: "IsSystem", - table: "AspNetRoles"); - - migrationBuilder.DropColumn( - name: "Permissions", - table: "AspNetRoles"); - - migrationBuilder.DropColumn( - name: "TenantId", - table: "AspNetRoles"); - } - } -} diff --git a/Data/Migrations/20260202064650_AddOAuthDescription.cs b/Data/Migrations/20260202064650_AddOAuthDescription.cs deleted file mode 100644 index 9f6d766..0000000 --- a/Data/Migrations/20260202064650_AddOAuthDescription.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace Fengling.AuthService.Data.Migrations -{ - /// - public partial class AddOAuthDescription : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "Description", - table: "OAuthApplications", - type: "character varying(500)", - maxLength: 500, - nullable: true); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropColumn( - name: "Description", - table: "OAuthApplications"); - } - } -} diff --git a/Data/SeedData.cs b/Data/SeedData.cs index ab2ca0c..67f8efc 100644 --- a/Data/SeedData.cs +++ b/Data/SeedData.cs @@ -13,7 +13,7 @@ public static class SeedData var userManager = scope.ServiceProvider.GetRequiredService>(); var roleManager = scope.ServiceProvider.GetRequiredService>(); - context.Database.EnsureCreated(); + await context.Database.EnsureCreatedAsync(); var defaultTenant = await context.Tenants .AsNoTracking() diff --git a/Data/Migrations/20260202064650_AddOAuthDescription.Designer.cs b/Migrations/20260205165820_InitialCreate.Designer.cs similarity index 94% rename from Data/Migrations/20260202064650_AddOAuthDescription.Designer.cs rename to Migrations/20260205165820_InitialCreate.Designer.cs index 47f017a..853405c 100644 --- a/Data/Migrations/20260202064650_AddOAuthDescription.Designer.cs +++ b/Migrations/20260205165820_InitialCreate.Designer.cs @@ -10,11 +10,11 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; #nullable disable -namespace Fengling.AuthService.Data.Migrations +namespace Fengling.AuthService.Migrations { [DbContext(typeof(ApplicationDbContext))] - [Migration("20260202064650_AddOAuthDescription")] - partial class AddOAuthDescription + [Migration("20260205165820_InitialCreate")] + partial class InitialCreate { /// protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -208,9 +208,6 @@ namespace Fengling.AuthService.Data.Migrations b.Property("SecurityStamp") .HasColumnType("text"); - b.Property("TenantId") - .HasColumnType("bigint"); - b.Property("TwoFactorEnabled") .HasColumnType("boolean"); @@ -233,8 +230,6 @@ namespace Fengling.AuthService.Data.Migrations b.HasIndex("Phone") .IsUnique(); - b.HasIndex("TenantId"); - b.ToTable("AspNetUsers", (string)null); }); @@ -557,10 +552,34 @@ namespace Fengling.AuthService.Data.Migrations modelBuilder.Entity("Fengling.AuthService.Models.ApplicationUser", b => { - b.HasOne("Fengling.AuthService.Models.Tenant", null) - .WithMany("Users") - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) + b.OwnsOne("Fengling.AuthService.Models.TenantInfo", "TenantInfo", b1 => + { + b1.Property("ApplicationUserId") + .HasColumnType("bigint"); + + b1.Property("Id") + .HasColumnType("bigint") + .HasColumnName("TenantId"); + + b1.Property("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("TenantName"); + + b1.Property("TenantId") + .IsRequired() + .HasColumnType("text") + .HasColumnName("TenantCode"); + + b1.HasKey("ApplicationUserId"); + + b1.ToTable("AspNetUsers"); + + b1.WithOwner() + .HasForeignKey("ApplicationUserId"); + }); + + b.Navigation("TenantInfo") .IsRequired(); }); @@ -614,11 +633,6 @@ namespace Fengling.AuthService.Data.Migrations .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - - modelBuilder.Entity("Fengling.AuthService.Models.Tenant", b => - { - b.Navigation("Users"); - }); #pragma warning restore 612, 618 } } diff --git a/Data/Migrations/20260201153600_InitialCreate.cs b/Migrations/20260205165820_InitialCreate.cs similarity index 52% rename from Data/Migrations/20260201153600_InitialCreate.cs rename to Migrations/20260205165820_InitialCreate.cs index d9e4db8..99261d1 100644 --- a/Data/Migrations/20260201153600_InitialCreate.cs +++ b/Migrations/20260205165820_InitialCreate.cs @@ -1,10 +1,11 @@ using System; +using System.Collections.Generic; using Microsoft.EntityFrameworkCore.Migrations; using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; #nullable disable -namespace Fengling.AuthService.Data.Migrations +namespace Fengling.AuthService.Migrations { /// public partial class InitialCreate : Migration @@ -12,6 +13,31 @@ namespace Fengling.AuthService.Data.Migrations /// protected override void Up(MigrationBuilder migrationBuilder) { + migrationBuilder.CreateTable( + name: "AccessLogs", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + UserName = table.Column(type: "character varying(50)", maxLength: 50, nullable: true), + TenantId = table.Column(type: "character varying(50)", maxLength: 50, nullable: true), + Action = table.Column(type: "character varying(20)", maxLength: 20, nullable: false), + Resource = table.Column(type: "character varying(200)", maxLength: 200, nullable: true), + Method = table.Column(type: "character varying(10)", maxLength: 10, nullable: true), + IpAddress = table.Column(type: "character varying(50)", maxLength: 50, nullable: true), + UserAgent = table.Column(type: "character varying(500)", maxLength: 500, nullable: true), + Status = table.Column(type: "character varying(20)", maxLength: 20, nullable: false), + Duration = table.Column(type: "integer", nullable: false), + RequestData = table.Column(type: "text", nullable: true), + ResponseData = table.Column(type: "text", nullable: true), + ErrorMessage = table.Column(type: "text", nullable: true), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AccessLogs", x => x.Id); + }); + migrationBuilder.CreateTable( name: "AspNetRoles", columns: table => new @@ -20,6 +46,10 @@ namespace Fengling.AuthService.Data.Migrations .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), Description = table.Column(type: "character varying(200)", maxLength: 200, nullable: true), CreatedTime = table.Column(type: "timestamp with time zone", nullable: false), + TenantId = table.Column(type: "bigint", nullable: true), + IsSystem = table.Column(type: "boolean", nullable: false), + DisplayName = table.Column(type: "text", nullable: true), + Permissions = table.Column>(type: "text[]", nullable: true), Name = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), NormalizedName = table.Column(type: "character varying(256)", maxLength: 256, nullable: true), ConcurrencyStamp = table.Column(type: "text", nullable: true) @@ -38,6 +68,8 @@ namespace Fengling.AuthService.Data.Migrations RealName = table.Column(type: "character varying(100)", maxLength: 100, nullable: true), Phone = table.Column(type: "character varying(20)", maxLength: 20, nullable: true), TenantId = table.Column(type: "bigint", nullable: false), + TenantCode = table.Column(type: "text", nullable: false), + TenantName = table.Column(type: "text", nullable: false), CreatedTime = table.Column(type: "timestamp with time zone", nullable: false), UpdatedTime = table.Column(type: "timestamp with time zone", nullable: true), IsDeleted = table.Column(type: "boolean", nullable: false), @@ -61,6 +93,81 @@ namespace Fengling.AuthService.Data.Migrations table.PrimaryKey("PK_AspNetUsers", x => x.Id); }); + migrationBuilder.CreateTable( + name: "AuditLogs", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + Operator = table.Column(type: "character varying(50)", maxLength: 50, nullable: false), + TenantId = table.Column(type: "character varying(50)", maxLength: 50, nullable: true), + Operation = table.Column(type: "character varying(20)", maxLength: 20, nullable: false), + Action = table.Column(type: "character varying(20)", maxLength: 20, nullable: false), + TargetType = table.Column(type: "character varying(50)", maxLength: 50, nullable: true), + TargetId = table.Column(type: "bigint", nullable: true), + TargetName = table.Column(type: "character varying(100)", maxLength: 100, nullable: true), + IpAddress = table.Column(type: "character varying(50)", maxLength: 50, nullable: false), + Description = table.Column(type: "character varying(500)", maxLength: 500, nullable: true), + OldValue = table.Column(type: "text", nullable: true), + NewValue = table.Column(type: "text", nullable: true), + ErrorMessage = table.Column(type: "text", nullable: true), + Status = table.Column(type: "character varying(20)", maxLength: 20, nullable: false), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AuditLogs", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "OAuthApplications", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + ClientId = table.Column(type: "character varying(100)", maxLength: 100, nullable: false), + ClientSecret = table.Column(type: "character varying(200)", maxLength: 200, nullable: true), + DisplayName = table.Column(type: "character varying(100)", maxLength: 100, nullable: false), + RedirectUris = table.Column(type: "text[]", nullable: false), + PostLogoutRedirectUris = table.Column(type: "text[]", nullable: false), + Scopes = table.Column(type: "text[]", nullable: false), + GrantTypes = table.Column(type: "text[]", nullable: false), + ClientType = table.Column(type: "character varying(20)", maxLength: 20, nullable: false), + ConsentType = table.Column(type: "character varying(20)", maxLength: 20, nullable: false), + Status = table.Column(type: "character varying(20)", maxLength: 20, nullable: false), + Description = table.Column(type: "character varying(500)", maxLength: 500, nullable: true), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), + UpdatedAt = table.Column(type: "timestamp with time zone", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_OAuthApplications", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Tenants", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + TenantId = table.Column(type: "character varying(50)", maxLength: 50, nullable: false), + Name = table.Column(type: "character varying(100)", maxLength: 100, nullable: false), + ContactName = table.Column(type: "character varying(50)", maxLength: 50, nullable: false), + ContactEmail = table.Column(type: "character varying(100)", maxLength: 100, nullable: false), + ContactPhone = table.Column(type: "character varying(20)", maxLength: 20, nullable: true), + MaxUsers = table.Column(type: "integer", nullable: true), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), + Description = table.Column(type: "character varying(500)", maxLength: 500, nullable: true), + Status = table.Column(type: "character varying(20)", maxLength: 20, nullable: false), + ExpiresAt = table.Column(type: "timestamp with time zone", nullable: true), + UpdatedAt = table.Column(type: "timestamp with time zone", nullable: true), + IsDeleted = table.Column(type: "boolean", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Tenants", x => x.Id); + }); + migrationBuilder.CreateTable( name: "AspNetRoleClaims", columns: table => new @@ -167,6 +274,31 @@ namespace Fengling.AuthService.Data.Migrations onDelete: ReferentialAction.Cascade); }); + migrationBuilder.CreateIndex( + name: "IX_AccessLogs_Action", + table: "AccessLogs", + column: "Action"); + + migrationBuilder.CreateIndex( + name: "IX_AccessLogs_CreatedAt", + table: "AccessLogs", + column: "CreatedAt"); + + migrationBuilder.CreateIndex( + name: "IX_AccessLogs_Status", + table: "AccessLogs", + column: "Status"); + + migrationBuilder.CreateIndex( + name: "IX_AccessLogs_TenantId", + table: "AccessLogs", + column: "TenantId"); + + migrationBuilder.CreateIndex( + name: "IX_AccessLogs_UserName", + table: "AccessLogs", + column: "UserName"); + migrationBuilder.CreateIndex( name: "IX_AspNetRoleClaims_RoleId", table: "AspNetRoleClaims", @@ -204,21 +336,56 @@ namespace Fengling.AuthService.Data.Migrations column: "Phone", unique: true); - migrationBuilder.CreateIndex( - name: "IX_AspNetUsers_TenantId", - table: "AspNetUsers", - column: "TenantId"); - migrationBuilder.CreateIndex( name: "UserNameIndex", table: "AspNetUsers", column: "NormalizedUserName", unique: true); + + migrationBuilder.CreateIndex( + name: "IX_AuditLogs_Action", + table: "AuditLogs", + column: "Action"); + + migrationBuilder.CreateIndex( + name: "IX_AuditLogs_CreatedAt", + table: "AuditLogs", + column: "CreatedAt"); + + migrationBuilder.CreateIndex( + name: "IX_AuditLogs_Operation", + table: "AuditLogs", + column: "Operation"); + + migrationBuilder.CreateIndex( + name: "IX_AuditLogs_Operator", + table: "AuditLogs", + column: "Operator"); + + migrationBuilder.CreateIndex( + name: "IX_AuditLogs_TenantId", + table: "AuditLogs", + column: "TenantId"); + + migrationBuilder.CreateIndex( + name: "IX_OAuthApplications_ClientId", + table: "OAuthApplications", + column: "ClientId", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Tenants_TenantId", + table: "Tenants", + column: "TenantId", + unique: true); } /// protected override void Down(MigrationBuilder migrationBuilder) { + migrationBuilder.DropTable( + name: "AccessLogs"); + migrationBuilder.DropTable( name: "AspNetRoleClaims"); @@ -234,6 +401,15 @@ namespace Fengling.AuthService.Data.Migrations migrationBuilder.DropTable( name: "AspNetUserTokens"); + migrationBuilder.DropTable( + name: "AuditLogs"); + + migrationBuilder.DropTable( + name: "OAuthApplications"); + + migrationBuilder.DropTable( + name: "Tenants"); + migrationBuilder.DropTable( name: "AspNetRoles"); diff --git a/Data/Migrations/ApplicationDbContextModelSnapshot.cs b/Migrations/ApplicationDbContextModelSnapshot.cs similarity index 94% rename from Data/Migrations/ApplicationDbContextModelSnapshot.cs rename to Migrations/ApplicationDbContextModelSnapshot.cs index 2dd38f3..7040b43 100644 --- a/Data/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/Migrations/ApplicationDbContextModelSnapshot.cs @@ -9,7 +9,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; #nullable disable -namespace Fengling.AuthService.Data.Migrations +namespace Fengling.AuthService.Migrations { [DbContext(typeof(ApplicationDbContext))] partial class ApplicationDbContextModelSnapshot : ModelSnapshot @@ -205,9 +205,6 @@ namespace Fengling.AuthService.Data.Migrations b.Property("SecurityStamp") .HasColumnType("text"); - b.Property("TenantId") - .HasColumnType("bigint"); - b.Property("TwoFactorEnabled") .HasColumnType("boolean"); @@ -230,8 +227,6 @@ namespace Fengling.AuthService.Data.Migrations b.HasIndex("Phone") .IsUnique(); - b.HasIndex("TenantId"); - b.ToTable("AspNetUsers", (string)null); }); @@ -554,10 +549,34 @@ namespace Fengling.AuthService.Data.Migrations modelBuilder.Entity("Fengling.AuthService.Models.ApplicationUser", b => { - b.HasOne("Fengling.AuthService.Models.Tenant", null) - .WithMany("Users") - .HasForeignKey("TenantId") - .OnDelete(DeleteBehavior.Cascade) + b.OwnsOne("Fengling.AuthService.Models.TenantInfo", "TenantInfo", b1 => + { + b1.Property("ApplicationUserId") + .HasColumnType("bigint"); + + b1.Property("Id") + .HasColumnType("bigint") + .HasColumnName("TenantId"); + + b1.Property("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("TenantName"); + + b1.Property("TenantId") + .IsRequired() + .HasColumnType("text") + .HasColumnName("TenantCode"); + + b1.HasKey("ApplicationUserId"); + + b1.ToTable("AspNetUsers"); + + b1.WithOwner() + .HasForeignKey("ApplicationUserId"); + }); + + b.Navigation("TenantInfo") .IsRequired(); }); @@ -611,11 +630,6 @@ namespace Fengling.AuthService.Data.Migrations .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - - modelBuilder.Entity("Fengling.AuthService.Models.Tenant", b => - { - b.Navigation("Users"); - }); #pragma warning restore 612, 618 } }