滑动续期与自动刷新:

Web:访问令牌 10 分钟;活跃时自动轮换刷新令牌;连续无操作 30 分钟后清除登录并跳转登录页。
App:会话窗口 3 天;打开 App、恢复前台或请求接口时自动刷新并重新顺延 3 天。
普通登录和 SSO 使用同一策略。
刷新令牌只以 SHA-256 摘要入库,每次刷新都会轮换,旧令牌无法再次使用;退出登录会吊销刷新令牌。
网络临时故障不会误清登录状态,多标签页同时刷新也做了竞争处理。
This commit is contained in:
2026-08-03 19:20:39 +08:00 Unverified
parent 6bee29a351
commit 5ec62a03ca
24 changed files with 6986 additions and 75 deletions
@@ -3297,6 +3297,7 @@ namespace Jiaowu.Api.Infrastructure.Persistence.Migrations.MySql
.HasColumnType("int");
b.Property<int>("Kind")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.HasDefaultValue(1);
@@ -4133,6 +4134,55 @@ namespace Jiaowu.Api.Infrastructure.Persistence.Migrations.MySql
b.ToTable("AspNetUsers", (string)null);
});
modelBuilder.Entity("Jiaowu.Api.Domain.Identity.RefreshSession", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("char(36)");
b.Property<string>("ClientType")
.IsRequired()
.HasMaxLength(20)
.HasColumnType("varchar(20)");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime(6)");
b.Property<DateTime>("ExpiresAt")
.HasColumnType("datetime(6)");
b.Property<DateTime>("LastRefreshedAt")
.HasColumnType("datetime(6)");
b.Property<Guid?>("ReplacedBySessionId")
.HasColumnType("char(36)");
b.Property<DateTime?>("RevokedAt")
.HasColumnType("datetime(6)");
b.Property<string>("SecurityStamp")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("varchar(100)");
b.Property<string>("TokenHash")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("varchar(64)");
b.Property<Guid>("UserId")
.HasColumnType("char(36)");
b.HasKey("Id");
b.HasIndex("TokenHash")
.IsUnique();
b.HasIndex("UserId", "ExpiresAt");
b.ToTable("RefreshSessions");
});
modelBuilder.Entity("Jiaowu.Api.Domain.System.AppUpdateRelease", b =>
{
b.Property<Guid>("Id")
@@ -5742,6 +5792,17 @@ namespace Jiaowu.Api.Infrastructure.Persistence.Migrations.MySql
b.Navigation("AcademicTerm");
});
modelBuilder.Entity("Jiaowu.Api.Domain.Identity.RefreshSession", b =>
{
b.HasOne("Jiaowu.Api.Domain.Identity.ApplicationUser", "User")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<System.Guid>", b =>
{
b.HasOne("Jiaowu.Api.Domain.Identity.ApplicationRole", null)