diff --git a/Directory.Packages.props b/Directory.Packages.props
index 14d249c..590345a 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -13,5 +13,6 @@
+
\ No newline at end of file
diff --git a/Fengling.Platform.Infrastructure/DesignTimeApplicationDbContextFactory.cs b/Fengling.Platform.Infrastructure/DesignTimeApplicationDbContextFactory.cs
index 0456bfe..8fe4613 100644
--- a/Fengling.Platform.Infrastructure/DesignTimeApplicationDbContextFactory.cs
+++ b/Fengling.Platform.Infrastructure/DesignTimeApplicationDbContextFactory.cs
@@ -18,6 +18,7 @@ public class DesignTimeApplicationDbContextFactory : IDesignTimeDbContextFactory
{
b.MigrationsAssembly(typeof(DesignTimeApplicationDbContextFactory).Assembly.FullName);
});
+ options.UseOpenIddict();
});
var provider = services.BuildServiceProvider();
var dbContext = provider.CreateScope().ServiceProvider.GetRequiredService();
diff --git a/Fengling.Platform.Infrastructure/Fengling.Platform.Infrastructure.csproj b/Fengling.Platform.Infrastructure/Fengling.Platform.Infrastructure.csproj
index a8c251e..5aef5b6 100644
--- a/Fengling.Platform.Infrastructure/Fengling.Platform.Infrastructure.csproj
+++ b/Fengling.Platform.Infrastructure/Fengling.Platform.Infrastructure.csproj
@@ -16,6 +16,7 @@
+
diff --git a/Fengling.Platform.Infrastructure/Migrations/20260221071055_OpenIddict.Designer.cs b/Fengling.Platform.Infrastructure/Migrations/20260221071055_OpenIddict.Designer.cs
new file mode 100644
index 0000000..7ab9aed
--- /dev/null
+++ b/Fengling.Platform.Infrastructure/Migrations/20260221071055_OpenIddict.Designer.cs
@@ -0,0 +1,809 @@
+//
+using System;
+using System.Collections.Generic;
+using Fengling.Platform.Infrastructure;
+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.Platform.Infrastructure.Migrations
+{
+ [DbContext(typeof(PlatformDbContext))]
+ [Migration("20260221071055_OpenIddict")]
+ partial class OpenIddict
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "10.0.0")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("Fengling.Platform.Domain.AggregatesModel.RoleAggregate.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.Platform.Domain.AggregatesModel.TenantAggregate.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("RowVersion")
+ .HasColumnType("bigint");
+
+ b.Property("Status")
+ .HasColumnType("integer");
+
+ b.Property("TenantCode")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("character varying(50)");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("timestamp with time zone");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Status");
+
+ b.HasIndex("TenantCode")
+ .IsUnique();
+
+ b.ToTable("Platform_Tenants", (string)null);
+ });
+
+ modelBuilder.Entity("Fengling.Platform.Domain.AggregatesModel.UserAggregate.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.Platform.Domain.AggregatesModel.UserAggregate.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("PhoneNumber")
+ .HasMaxLength(20)
+ .HasColumnType("character varying(20)");
+
+ b.Property("PhoneNumberConfirmed")
+ .HasColumnType("boolean");
+
+ b.Property("RealName")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("SecurityStamp")
+ .HasColumnType("text");
+
+ 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("PhoneNumber")
+ .IsUnique();
+
+ b.ToTable("AspNetUsers", (string)null);
+ });
+
+ modelBuilder.Entity("Fengling.Platform.Domain.AggregatesModel.UserAggregate.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("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("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreApplication", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("text");
+
+ b.Property("ApplicationType")
+ .HasMaxLength(50)
+ .HasColumnType("character varying(50)");
+
+ b.Property("ClientId")
+ .HasMaxLength(100)
+ .HasColumnType("character varying(100)");
+
+ b.Property("ClientSecret")
+ .HasColumnType("text");
+
+ b.Property("ClientType")
+ .HasMaxLength(50)
+ .HasColumnType("character varying(50)");
+
+ b.Property("ConcurrencyToken")
+ .IsConcurrencyToken()
+ .HasMaxLength(50)
+ .HasColumnType("character varying(50)");
+
+ b.Property("ConsentType")
+ .HasMaxLength(50)
+ .HasColumnType("character varying(50)");
+
+ b.Property("DisplayName")
+ .HasColumnType("text");
+
+ b.Property("DisplayNames")
+ .HasColumnType("text");
+
+ b.Property("JsonWebKeySet")
+ .HasColumnType("text");
+
+ b.Property("Permissions")
+ .HasColumnType("text");
+
+ b.Property("PostLogoutRedirectUris")
+ .HasColumnType("text");
+
+ b.Property("Properties")
+ .HasColumnType("text");
+
+ b.Property("RedirectUris")
+ .HasColumnType("text");
+
+ b.Property("Requirements")
+ .HasColumnType("text");
+
+ b.Property("Settings")
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ClientId")
+ .IsUnique();
+
+ b.ToTable("OpenIddictApplications", (string)null);
+ });
+
+ modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreAuthorization", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("text");
+
+ b.Property("ApplicationId")
+ .HasColumnType("text");
+
+ b.Property("ConcurrencyToken")
+ .IsConcurrencyToken()
+ .HasMaxLength(50)
+ .HasColumnType("character varying(50)");
+
+ b.Property("CreationDate")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Properties")
+ .HasColumnType("text");
+
+ b.Property("Scopes")
+ .HasColumnType("text");
+
+ b.Property("Status")
+ .HasMaxLength(50)
+ .HasColumnType("character varying(50)");
+
+ b.Property("Subject")
+ .HasMaxLength(400)
+ .HasColumnType("character varying(400)");
+
+ b.Property("Type")
+ .HasMaxLength(50)
+ .HasColumnType("character varying(50)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ApplicationId", "Status", "Subject", "Type");
+
+ b.ToTable("OpenIddictAuthorizations", (string)null);
+ });
+
+ modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreScope", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("text");
+
+ b.Property("ConcurrencyToken")
+ .IsConcurrencyToken()
+ .HasMaxLength(50)
+ .HasColumnType("character varying(50)");
+
+ b.Property("Description")
+ .HasColumnType("text");
+
+ b.Property("Descriptions")
+ .HasColumnType("text");
+
+ b.Property("DisplayName")
+ .HasColumnType("text");
+
+ b.Property("DisplayNames")
+ .HasColumnType("text");
+
+ b.Property("Name")
+ .HasMaxLength(200)
+ .HasColumnType("character varying(200)");
+
+ b.Property("Properties")
+ .HasColumnType("text");
+
+ b.Property("Resources")
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Name")
+ .IsUnique();
+
+ b.ToTable("OpenIddictScopes", (string)null);
+ });
+
+ modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreToken", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("text");
+
+ b.Property("ApplicationId")
+ .HasColumnType("text");
+
+ b.Property("AuthorizationId")
+ .HasColumnType("text");
+
+ b.Property("ConcurrencyToken")
+ .IsConcurrencyToken()
+ .HasMaxLength(50)
+ .HasColumnType("character varying(50)");
+
+ b.Property("CreationDate")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("ExpirationDate")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Payload")
+ .HasColumnType("text");
+
+ b.Property("Properties")
+ .HasColumnType("text");
+
+ b.Property("RedemptionDate")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("ReferenceId")
+ .HasMaxLength(100)
+ .HasColumnType("character varying(100)");
+
+ b.Property("Status")
+ .HasMaxLength(50)
+ .HasColumnType("character varying(50)");
+
+ b.Property("Subject")
+ .HasMaxLength(400)
+ .HasColumnType("character varying(400)");
+
+ b.Property("Type")
+ .HasMaxLength(150)
+ .HasColumnType("character varying(150)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("AuthorizationId");
+
+ b.HasIndex("ReferenceId")
+ .IsUnique();
+
+ b.HasIndex("ApplicationId", "Status", "Subject", "Type");
+
+ b.ToTable("OpenIddictTokens", (string)null);
+ });
+
+ modelBuilder.Entity("Fengling.Platform.Domain.AggregatesModel.UserAggregate.ApplicationUser", b =>
+ {
+ b.OwnsOne("Fengling.Platform.Domain.AggregatesModel.TenantAggregate.TenantInfo", "TenantInfo", b1 =>
+ {
+ b1.Property("ApplicationUserId")
+ .HasColumnType("bigint");
+
+ b1.Property("TenantCode")
+ .HasColumnType("text")
+ .HasColumnName("TenantCode");
+
+ b1.Property("TenantId")
+ .HasColumnType("bigint")
+ .HasColumnName("TenantId");
+
+ b1.Property("TenantName")
+ .HasColumnType("text")
+ .HasColumnName("TenantName");
+
+ b1.HasKey("ApplicationUserId");
+
+ b1.ToTable("AspNetUsers");
+
+ b1.WithOwner()
+ .HasForeignKey("ApplicationUserId");
+ });
+
+ b.Navigation("TenantInfo");
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b =>
+ {
+ b.HasOne("Fengling.Platform.Domain.AggregatesModel.RoleAggregate.ApplicationRole", null)
+ .WithMany()
+ .HasForeignKey("RoleId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b =>
+ {
+ b.HasOne("Fengling.Platform.Domain.AggregatesModel.UserAggregate.ApplicationUser", null)
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b =>
+ {
+ b.HasOne("Fengling.Platform.Domain.AggregatesModel.UserAggregate.ApplicationUser", null)
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b =>
+ {
+ b.HasOne("Fengling.Platform.Domain.AggregatesModel.RoleAggregate.ApplicationRole", null)
+ .WithMany()
+ .HasForeignKey("RoleId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Fengling.Platform.Domain.AggregatesModel.UserAggregate.ApplicationUser", null)
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b =>
+ {
+ b.HasOne("Fengling.Platform.Domain.AggregatesModel.UserAggregate.ApplicationUser", null)
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreAuthorization", b =>
+ {
+ b.HasOne("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreApplication", "Application")
+ .WithMany("Authorizations")
+ .HasForeignKey("ApplicationId");
+
+ b.Navigation("Application");
+ });
+
+ modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreToken", b =>
+ {
+ b.HasOne("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreApplication", "Application")
+ .WithMany("Tokens")
+ .HasForeignKey("ApplicationId");
+
+ b.HasOne("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreAuthorization", "Authorization")
+ .WithMany("Tokens")
+ .HasForeignKey("AuthorizationId");
+
+ b.Navigation("Application");
+
+ b.Navigation("Authorization");
+ });
+
+ modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreApplication", b =>
+ {
+ b.Navigation("Authorizations");
+
+ b.Navigation("Tokens");
+ });
+
+ modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreAuthorization", b =>
+ {
+ b.Navigation("Tokens");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/Fengling.Platform.Infrastructure/Migrations/20260221071055_OpenIddict.cs b/Fengling.Platform.Infrastructure/Migrations/20260221071055_OpenIddict.cs
new file mode 100644
index 0000000..a1d72d2
--- /dev/null
+++ b/Fengling.Platform.Infrastructure/Migrations/20260221071055_OpenIddict.cs
@@ -0,0 +1,166 @@
+using System;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace Fengling.Platform.Infrastructure.Migrations
+{
+ ///
+ public partial class OpenIddict : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.CreateTable(
+ name: "OpenIddictApplications",
+ columns: table => new
+ {
+ Id = table.Column(type: "text", nullable: false),
+ ApplicationType = table.Column(type: "character varying(50)", maxLength: 50, nullable: true),
+ ClientId = table.Column(type: "character varying(100)", maxLength: 100, nullable: true),
+ ClientSecret = table.Column(type: "text", nullable: true),
+ ClientType = table.Column(type: "character varying(50)", maxLength: 50, nullable: true),
+ ConcurrencyToken = table.Column(type: "character varying(50)", maxLength: 50, nullable: true),
+ ConsentType = table.Column(type: "character varying(50)", maxLength: 50, nullable: true),
+ DisplayName = table.Column(type: "text", nullable: true),
+ DisplayNames = table.Column(type: "text", nullable: true),
+ JsonWebKeySet = table.Column(type: "text", nullable: true),
+ Permissions = table.Column(type: "text", nullable: true),
+ PostLogoutRedirectUris = table.Column(type: "text", nullable: true),
+ Properties = table.Column(type: "text", nullable: true),
+ RedirectUris = table.Column(type: "text", nullable: true),
+ Requirements = table.Column(type: "text", nullable: true),
+ Settings = table.Column(type: "text", nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_OpenIddictApplications", x => x.Id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "OpenIddictScopes",
+ columns: table => new
+ {
+ Id = table.Column(type: "text", nullable: false),
+ ConcurrencyToken = table.Column(type: "character varying(50)", maxLength: 50, nullable: true),
+ Description = table.Column(type: "text", nullable: true),
+ Descriptions = table.Column(type: "text", nullable: true),
+ DisplayName = table.Column(type: "text", nullable: true),
+ DisplayNames = table.Column(type: "text", nullable: true),
+ Name = table.Column(type: "character varying(200)", maxLength: 200, nullable: true),
+ Properties = table.Column(type: "text", nullable: true),
+ Resources = table.Column(type: "text", nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_OpenIddictScopes", x => x.Id);
+ });
+
+ migrationBuilder.CreateTable(
+ name: "OpenIddictAuthorizations",
+ columns: table => new
+ {
+ Id = table.Column(type: "text", nullable: false),
+ ApplicationId = table.Column(type: "text", nullable: true),
+ ConcurrencyToken = table.Column(type: "character varying(50)", maxLength: 50, nullable: true),
+ CreationDate = table.Column(type: "timestamp with time zone", nullable: true),
+ Properties = table.Column(type: "text", nullable: true),
+ Scopes = table.Column(type: "text", nullable: true),
+ Status = table.Column(type: "character varying(50)", maxLength: 50, nullable: true),
+ Subject = table.Column(type: "character varying(400)", maxLength: 400, nullable: true),
+ Type = table.Column(type: "character varying(50)", maxLength: 50, nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_OpenIddictAuthorizations", x => x.Id);
+ table.ForeignKey(
+ name: "FK_OpenIddictAuthorizations_OpenIddictApplications_Application~",
+ column: x => x.ApplicationId,
+ principalTable: "OpenIddictApplications",
+ principalColumn: "Id");
+ });
+
+ migrationBuilder.CreateTable(
+ name: "OpenIddictTokens",
+ columns: table => new
+ {
+ Id = table.Column(type: "text", nullable: false),
+ ApplicationId = table.Column(type: "text", nullable: true),
+ AuthorizationId = table.Column(type: "text", nullable: true),
+ ConcurrencyToken = table.Column(type: "character varying(50)", maxLength: 50, nullable: true),
+ CreationDate = table.Column(type: "timestamp with time zone", nullable: true),
+ ExpirationDate = table.Column(type: "timestamp with time zone", nullable: true),
+ Payload = table.Column(type: "text", nullable: true),
+ Properties = table.Column(type: "text", nullable: true),
+ RedemptionDate = table.Column(type: "timestamp with time zone", nullable: true),
+ ReferenceId = table.Column(type: "character varying(100)", maxLength: 100, nullable: true),
+ Status = table.Column(type: "character varying(50)", maxLength: 50, nullable: true),
+ Subject = table.Column(type: "character varying(400)", maxLength: 400, nullable: true),
+ Type = table.Column(type: "character varying(150)", maxLength: 150, nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_OpenIddictTokens", x => x.Id);
+ table.ForeignKey(
+ name: "FK_OpenIddictTokens_OpenIddictApplications_ApplicationId",
+ column: x => x.ApplicationId,
+ principalTable: "OpenIddictApplications",
+ principalColumn: "Id");
+ table.ForeignKey(
+ name: "FK_OpenIddictTokens_OpenIddictAuthorizations_AuthorizationId",
+ column: x => x.AuthorizationId,
+ principalTable: "OpenIddictAuthorizations",
+ principalColumn: "Id");
+ });
+
+ migrationBuilder.CreateIndex(
+ name: "IX_OpenIddictApplications_ClientId",
+ table: "OpenIddictApplications",
+ column: "ClientId",
+ unique: true);
+
+ migrationBuilder.CreateIndex(
+ name: "IX_OpenIddictAuthorizations_ApplicationId_Status_Subject_Type",
+ table: "OpenIddictAuthorizations",
+ columns: new[] { "ApplicationId", "Status", "Subject", "Type" });
+
+ migrationBuilder.CreateIndex(
+ name: "IX_OpenIddictScopes_Name",
+ table: "OpenIddictScopes",
+ column: "Name",
+ unique: true);
+
+ migrationBuilder.CreateIndex(
+ name: "IX_OpenIddictTokens_ApplicationId_Status_Subject_Type",
+ table: "OpenIddictTokens",
+ columns: new[] { "ApplicationId", "Status", "Subject", "Type" });
+
+ migrationBuilder.CreateIndex(
+ name: "IX_OpenIddictTokens_AuthorizationId",
+ table: "OpenIddictTokens",
+ column: "AuthorizationId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_OpenIddictTokens_ReferenceId",
+ table: "OpenIddictTokens",
+ column: "ReferenceId",
+ unique: true);
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropTable(
+ name: "OpenIddictScopes");
+
+ migrationBuilder.DropTable(
+ name: "OpenIddictTokens");
+
+ migrationBuilder.DropTable(
+ name: "OpenIddictAuthorizations");
+
+ migrationBuilder.DropTable(
+ name: "OpenIddictApplications");
+ }
+ }
+}
diff --git a/Fengling.Platform.Infrastructure/Migrations/PlatformDbContextModelSnapshot.cs b/Fengling.Platform.Infrastructure/Migrations/PlatformDbContextModelSnapshot.cs
index d2764de..f9ee507 100644
--- a/Fengling.Platform.Infrastructure/Migrations/PlatformDbContextModelSnapshot.cs
+++ b/Fengling.Platform.Infrastructure/Migrations/PlatformDbContextModelSnapshot.cs
@@ -476,6 +476,214 @@ namespace Fengling.Platform.Infrastructure.Migrations
b.ToTable("AspNetUserTokens", (string)null);
});
+ modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreApplication", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("text");
+
+ b.Property("ApplicationType")
+ .HasMaxLength(50)
+ .HasColumnType("character varying(50)");
+
+ b.Property("ClientId")
+ .HasMaxLength(100)
+ .HasColumnType("character varying(100)");
+
+ b.Property("ClientSecret")
+ .HasColumnType("text");
+
+ b.Property("ClientType")
+ .HasMaxLength(50)
+ .HasColumnType("character varying(50)");
+
+ b.Property("ConcurrencyToken")
+ .IsConcurrencyToken()
+ .HasMaxLength(50)
+ .HasColumnType("character varying(50)");
+
+ b.Property("ConsentType")
+ .HasMaxLength(50)
+ .HasColumnType("character varying(50)");
+
+ b.Property("DisplayName")
+ .HasColumnType("text");
+
+ b.Property("DisplayNames")
+ .HasColumnType("text");
+
+ b.Property("JsonWebKeySet")
+ .HasColumnType("text");
+
+ b.Property("Permissions")
+ .HasColumnType("text");
+
+ b.Property("PostLogoutRedirectUris")
+ .HasColumnType("text");
+
+ b.Property("Properties")
+ .HasColumnType("text");
+
+ b.Property("RedirectUris")
+ .HasColumnType("text");
+
+ b.Property("Requirements")
+ .HasColumnType("text");
+
+ b.Property("Settings")
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ClientId")
+ .IsUnique();
+
+ b.ToTable("OpenIddictApplications", (string)null);
+ });
+
+ modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreAuthorization", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("text");
+
+ b.Property("ApplicationId")
+ .HasColumnType("text");
+
+ b.Property("ConcurrencyToken")
+ .IsConcurrencyToken()
+ .HasMaxLength(50)
+ .HasColumnType("character varying(50)");
+
+ b.Property("CreationDate")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Properties")
+ .HasColumnType("text");
+
+ b.Property("Scopes")
+ .HasColumnType("text");
+
+ b.Property("Status")
+ .HasMaxLength(50)
+ .HasColumnType("character varying(50)");
+
+ b.Property("Subject")
+ .HasMaxLength(400)
+ .HasColumnType("character varying(400)");
+
+ b.Property("Type")
+ .HasMaxLength(50)
+ .HasColumnType("character varying(50)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ApplicationId", "Status", "Subject", "Type");
+
+ b.ToTable("OpenIddictAuthorizations", (string)null);
+ });
+
+ modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreScope", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("text");
+
+ b.Property("ConcurrencyToken")
+ .IsConcurrencyToken()
+ .HasMaxLength(50)
+ .HasColumnType("character varying(50)");
+
+ b.Property("Description")
+ .HasColumnType("text");
+
+ b.Property("Descriptions")
+ .HasColumnType("text");
+
+ b.Property("DisplayName")
+ .HasColumnType("text");
+
+ b.Property("DisplayNames")
+ .HasColumnType("text");
+
+ b.Property("Name")
+ .HasMaxLength(200)
+ .HasColumnType("character varying(200)");
+
+ b.Property("Properties")
+ .HasColumnType("text");
+
+ b.Property("Resources")
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Name")
+ .IsUnique();
+
+ b.ToTable("OpenIddictScopes", (string)null);
+ });
+
+ modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreToken", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("text");
+
+ b.Property("ApplicationId")
+ .HasColumnType("text");
+
+ b.Property("AuthorizationId")
+ .HasColumnType("text");
+
+ b.Property("ConcurrencyToken")
+ .IsConcurrencyToken()
+ .HasMaxLength(50)
+ .HasColumnType("character varying(50)");
+
+ b.Property("CreationDate")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("ExpirationDate")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Payload")
+ .HasColumnType("text");
+
+ b.Property("Properties")
+ .HasColumnType("text");
+
+ b.Property("RedemptionDate")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("ReferenceId")
+ .HasMaxLength(100)
+ .HasColumnType("character varying(100)");
+
+ b.Property("Status")
+ .HasMaxLength(50)
+ .HasColumnType("character varying(50)");
+
+ b.Property("Subject")
+ .HasMaxLength(400)
+ .HasColumnType("character varying(400)");
+
+ b.Property("Type")
+ .HasMaxLength(150)
+ .HasColumnType("character varying(150)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("AuthorizationId");
+
+ b.HasIndex("ReferenceId")
+ .IsUnique();
+
+ b.HasIndex("ApplicationId", "Status", "Subject", "Type");
+
+ b.ToTable("OpenIddictTokens", (string)null);
+ });
+
modelBuilder.Entity("Fengling.Platform.Domain.AggregatesModel.UserAggregate.ApplicationUser", b =>
{
b.OwnsOne("Fengling.Platform.Domain.AggregatesModel.TenantAggregate.TenantInfo", "TenantInfo", b1 =>
@@ -556,6 +764,42 @@ namespace Fengling.Platform.Infrastructure.Migrations
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
+
+ modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreAuthorization", b =>
+ {
+ b.HasOne("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreApplication", "Application")
+ .WithMany("Authorizations")
+ .HasForeignKey("ApplicationId");
+
+ b.Navigation("Application");
+ });
+
+ modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreToken", b =>
+ {
+ b.HasOne("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreApplication", "Application")
+ .WithMany("Tokens")
+ .HasForeignKey("ApplicationId");
+
+ b.HasOne("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreAuthorization", "Authorization")
+ .WithMany("Tokens")
+ .HasForeignKey("AuthorizationId");
+
+ b.Navigation("Application");
+
+ b.Navigation("Authorization");
+ });
+
+ modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreApplication", b =>
+ {
+ b.Navigation("Authorizations");
+
+ b.Navigation("Tokens");
+ });
+
+ modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreAuthorization", b =>
+ {
+ b.Navigation("Tokens");
+ });
#pragma warning restore 612, 618
}
}
diff --git a/Fengling.Platform.Infrastructure/Migrations/sql/20260221_openiddict.sql b/Fengling.Platform.Infrastructure/Migrations/sql/20260221_openiddict.sql
new file mode 100644
index 0000000..eed7412
--- /dev/null
+++ b/Fengling.Platform.Infrastructure/Migrations/sql/20260221_openiddict.sql
@@ -0,0 +1,84 @@
+START TRANSACTION;
+CREATE TABLE "OpenIddictApplications" (
+ "Id" text NOT NULL,
+ "ApplicationType" character varying(50),
+ "ClientId" character varying(100),
+ "ClientSecret" text,
+ "ClientType" character varying(50),
+ "ConcurrencyToken" character varying(50),
+ "ConsentType" character varying(50),
+ "DisplayName" text,
+ "DisplayNames" text,
+ "JsonWebKeySet" text,
+ "Permissions" text,
+ "PostLogoutRedirectUris" text,
+ "Properties" text,
+ "RedirectUris" text,
+ "Requirements" text,
+ "Settings" text,
+ CONSTRAINT "PK_OpenIddictApplications" PRIMARY KEY ("Id")
+);
+
+CREATE TABLE "OpenIddictScopes" (
+ "Id" text NOT NULL,
+ "ConcurrencyToken" character varying(50),
+ "Description" text,
+ "Descriptions" text,
+ "DisplayName" text,
+ "DisplayNames" text,
+ "Name" character varying(200),
+ "Properties" text,
+ "Resources" text,
+ CONSTRAINT "PK_OpenIddictScopes" PRIMARY KEY ("Id")
+);
+
+CREATE TABLE "OpenIddictAuthorizations" (
+ "Id" text NOT NULL,
+ "ApplicationId" text,
+ "ConcurrencyToken" character varying(50),
+ "CreationDate" timestamp with time zone,
+ "Properties" text,
+ "Scopes" text,
+ "Status" character varying(50),
+ "Subject" character varying(400),
+ "Type" character varying(50),
+ CONSTRAINT "PK_OpenIddictAuthorizations" PRIMARY KEY ("Id"),
+ CONSTRAINT "FK_OpenIddictAuthorizations_OpenIddictApplications_Application~" FOREIGN KEY ("ApplicationId") REFERENCES "OpenIddictApplications" ("Id")
+);
+
+CREATE TABLE "OpenIddictTokens" (
+ "Id" text NOT NULL,
+ "ApplicationId" text,
+ "AuthorizationId" text,
+ "ConcurrencyToken" character varying(50),
+ "CreationDate" timestamp with time zone,
+ "ExpirationDate" timestamp with time zone,
+ "Payload" text,
+ "Properties" text,
+ "RedemptionDate" timestamp with time zone,
+ "ReferenceId" character varying(100),
+ "Status" character varying(50),
+ "Subject" character varying(400),
+ "Type" character varying(150),
+ CONSTRAINT "PK_OpenIddictTokens" PRIMARY KEY ("Id"),
+ CONSTRAINT "FK_OpenIddictTokens_OpenIddictApplications_ApplicationId" FOREIGN KEY ("ApplicationId") REFERENCES "OpenIddictApplications" ("Id"),
+ CONSTRAINT "FK_OpenIddictTokens_OpenIddictAuthorizations_AuthorizationId" FOREIGN KEY ("AuthorizationId") REFERENCES "OpenIddictAuthorizations" ("Id")
+);
+
+CREATE UNIQUE INDEX "IX_OpenIddictApplications_ClientId" ON "OpenIddictApplications" ("ClientId");
+
+CREATE INDEX "IX_OpenIddictAuthorizations_ApplicationId_Status_Subject_Type" ON "OpenIddictAuthorizations" ("ApplicationId", "Status", "Subject", "Type");
+
+CREATE UNIQUE INDEX "IX_OpenIddictScopes_Name" ON "OpenIddictScopes" ("Name");
+
+CREATE INDEX "IX_OpenIddictTokens_ApplicationId_Status_Subject_Type" ON "OpenIddictTokens" ("ApplicationId", "Status", "Subject", "Type");
+
+CREATE INDEX "IX_OpenIddictTokens_AuthorizationId" ON "OpenIddictTokens" ("AuthorizationId");
+
+CREATE UNIQUE INDEX "IX_OpenIddictTokens_ReferenceId" ON "OpenIddictTokens" ("ReferenceId");
+
+INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
+VALUES ('20260221071055_OpenIddict', '10.0.0');
+
+COMMIT;
+