feat: add data protection key management and update authentication settings
- Added support for data protection keys by integrating Entity Framework Core for key persistence. - Updated `Program.cs` and `MemberCenterDbContext.cs` to configure data protection services. - Introduced new migration to create `DataProtectionKeys` table in the database. - Enhanced cookie settings for authentication to enforce security policies (SameSite=None, Secure=Always). - Updated installation documentation with new authentication configuration options.
This commit is contained in:
parent
e77fdec76b
commit
6729f91275
@ -41,6 +41,9 @@
|
||||
ASPNETCORE_ENVIRONMENT=Development
|
||||
ConnectionStrings__Default=Host=localhost;Database=member_center;Username=postgres;Password=postgres
|
||||
Auth__Issuer=http://localhost:7850/
|
||||
Auth__WebLoginUrl=http://localhost:5080/account/login
|
||||
Auth__AllowedLoginReturnUrlPrefixes=http://localhost:7850/
|
||||
Auth__AllowedLogoutReturnUrlPrefixes=http://localhost:5243/
|
||||
Auth__Resources__MemberCenter__Audience=member_center_api
|
||||
Auth__Resources__SendEngine__Audience=send_engine_api
|
||||
Auth__Resources__FileAccess__Audience=file_access_api
|
||||
@ -59,6 +62,12 @@ SendEngine__WebhookSecret=change-me
|
||||
- 規劃上將收斂為 DB resource registry;`.env` 僅作為初始 seed / 部署覆寫來源,不應再為每個新服務新增平行 hardcoded key。
|
||||
- `File Access` 已直接採用 resource registry 形式,不新增第三組硬編碼 audience 判斷。
|
||||
|
||||
OIDC / Redirect login 設定說明:
|
||||
- `Auth__WebLoginUrl`: API `/oauth/authorize` 未登入時導向的 Web login URL。
|
||||
- `Auth__AllowedLoginReturnUrlPrefixes`: Web login 成功後允許 redirect 回去的 URL prefix,通常填 API issuer/base URL。
|
||||
- `Auth__AllowedLogoutReturnUrlPrefixes`: Web logout 後允許 redirect 的 URL prefix。
|
||||
- Identity cookie 固定使用 `SameSite=None`、`Secure=Always`、`Path=/`,因此 stage/prod 必須使用 HTTPS。
|
||||
|
||||
`SendEngine` 設定說明:
|
||||
- `SendEngine__BaseUrl`: Send Engine API base URL
|
||||
- `SendEngine__WebhookSecret`: 與 Send Engine `Webhook:Secrets:member_center` 一致
|
||||
|
||||
@ -25,7 +25,8 @@ var issuerUri = ParseAbsoluteUriOrThrow(issuer, "Auth:Issuer");
|
||||
var allowInsecureHttp = builder.Configuration.GetValue("Auth:AllowInsecureHttp", false);
|
||||
|
||||
builder.Services.AddDataProtection()
|
||||
.SetApplicationName("MemberCenter");
|
||||
.SetApplicationName("MemberCenter")
|
||||
.PersistKeysToDbContext<MemberCenterDbContext>();
|
||||
|
||||
builder.Services.AddDbContext<MemberCenterDbContext>(options =>
|
||||
{
|
||||
@ -61,11 +62,9 @@ builder.Services.AddAuthentication(options =>
|
||||
|
||||
builder.Services.ConfigureApplicationCookie(options =>
|
||||
{
|
||||
var cookieDomain = builder.Configuration["Auth:CookieDomain"];
|
||||
if (!string.IsNullOrWhiteSpace(cookieDomain))
|
||||
{
|
||||
options.Cookie.Domain = cookieDomain;
|
||||
}
|
||||
options.Cookie.Path = "/";
|
||||
options.Cookie.SameSite = SameSiteMode.None;
|
||||
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
|
||||
});
|
||||
|
||||
builder.Services.AddOpenIddict()
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.DataProtection.EntityFrameworkCore" Version="8.0.11" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.11" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.11" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.11">
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
using MemberCenter.Domain.Entities;
|
||||
using MemberCenter.Infrastructure.Identity;
|
||||
using Microsoft.AspNetCore.DataProtection.EntityFrameworkCore;
|
||||
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace MemberCenter.Infrastructure.Persistence;
|
||||
|
||||
public class MemberCenterDbContext
|
||||
: IdentityDbContext<ApplicationUser, ApplicationRole, Guid>
|
||||
: IdentityDbContext<ApplicationUser, ApplicationRole, Guid>, IDataProtectionKeyContext
|
||||
{
|
||||
public MemberCenterDbContext(DbContextOptions<MemberCenterDbContext> options)
|
||||
: base(options)
|
||||
@ -27,6 +28,7 @@ public class MemberCenterDbContext
|
||||
public DbSet<AuthResourceScope> AuthResourceScopes => Set<AuthResourceScope>();
|
||||
public DbSet<AuthClientUsagePermission> AuthClientUsagePermissions => Set<AuthClientUsagePermission>();
|
||||
public DbSet<FileAccessDownloadToken> FileAccessDownloadTokens => Set<FileAccessDownloadToken>();
|
||||
public DbSet<DataProtectionKey> DataProtectionKeys { get; set; } = null!;
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder builder)
|
||||
{
|
||||
|
||||
1321
src/MemberCenter.Infrastructure/Persistence/Migrations/20260430200729_AddDataProtectionKeys.Designer.cs
generated
Normal file
1321
src/MemberCenter.Infrastructure/Persistence/Migrations/20260430200729_AddDataProtectionKeys.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,36 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace MemberCenter.Infrastructure.Persistence.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddDataProtectionKeys : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "DataProtectionKeys",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
FriendlyName = table.Column<string>(type: "text", nullable: true),
|
||||
Xml = table.Column<string>(type: "text", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_DataProtectionKeys", x => x.Id);
|
||||
});
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "DataProtectionKeys");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -783,6 +783,25 @@ namespace MemberCenter.Infrastructure.Persistence.Migrations
|
||||
b.ToTable("users", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.DataProtectionKey", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("FriendlyName")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Xml")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("DataProtectionKeys");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<System.Guid>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
|
||||
@ -19,7 +19,8 @@ EnvLoader.LoadDotEnvIfDevelopment();
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
builder.Services.AddDataProtection()
|
||||
.SetApplicationName("MemberCenter");
|
||||
.SetApplicationName("MemberCenter")
|
||||
.PersistKeysToDbContext<MemberCenterDbContext>();
|
||||
|
||||
builder.Services.AddDbContext<MemberCenterDbContext>(options =>
|
||||
{
|
||||
@ -70,11 +71,9 @@ if (!string.IsNullOrWhiteSpace(googleClientId) && !string.IsNullOrWhiteSpace(goo
|
||||
builder.Services.ConfigureApplicationCookie(options =>
|
||||
{
|
||||
options.LoginPath = "/account/login";
|
||||
var cookieDomain = builder.Configuration["Auth:CookieDomain"];
|
||||
if (!string.IsNullOrWhiteSpace(cookieDomain))
|
||||
{
|
||||
options.Cookie.Domain = cookieDomain;
|
||||
}
|
||||
options.Cookie.Path = "/";
|
||||
options.Cookie.SameSite = SameSiteMode.None;
|
||||
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
|
||||
|
||||
options.Events = new CookieAuthenticationEvents
|
||||
{
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user