forked from xiongyuxing/tiku-backend.net
feat: harden SaaS authentication and authorization
This commit is contained in:
@@ -1,20 +1,35 @@
|
||||
using System.Text.Json;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Tiku.Domain.Common;
|
||||
|
||||
namespace Tiku.Domain.Identity;
|
||||
|
||||
public sealed class User : AuditableEntity
|
||||
public sealed class User : IdentityUser<Guid>, IHasTimestamps
|
||||
{
|
||||
public User()
|
||||
{
|
||||
Id = Guid.NewGuid();
|
||||
SecurityStamp = Guid.NewGuid().ToString("N");
|
||||
ConcurrencyStamp = Guid.NewGuid().ToString("N");
|
||||
}
|
||||
|
||||
public string? LegacyId { get; set; }
|
||||
public string? Username { get; set; }
|
||||
public string? Email { get; set; }
|
||||
public string? Phone { get; set; }
|
||||
public string? Name { get; set; }
|
||||
public string? AvatarUrl { get; set; }
|
||||
public string PrimaryRole { get; set; } = "student";
|
||||
public int Score { get; set; }
|
||||
public DateTimeOffset? LastSeenAt { get; set; }
|
||||
public string? LegacyPasswordHash { get; set; }
|
||||
public bool PasswordMigrationRequired { get; set; }
|
||||
public UserStatus Status { get; set; } = UserStatus.Active;
|
||||
public bool ForcePasswordChange { get; set; }
|
||||
public JsonElement RawProfile { get; set; } = JsonDefaults.Object();
|
||||
public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow;
|
||||
public DateTimeOffset UpdatedAt { get; set; } = DateTimeOffset.UtcNow;
|
||||
}
|
||||
|
||||
public enum UserStatus
|
||||
{
|
||||
Active,
|
||||
Disabled,
|
||||
Archived
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using System.Text.Json;
|
||||
using Tiku.Domain.Common;
|
||||
|
||||
namespace Tiku.Domain.Identity;
|
||||
@@ -12,5 +11,4 @@ public sealed class UserIdentity : AuditableEntity
|
||||
public string? OpenId { get; set; }
|
||||
public string? Phone { get; set; }
|
||||
public string? Email { get; set; }
|
||||
public JsonElement SecretPayload { get; set; } = JsonDefaults.Object();
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using System.Text.Json;
|
||||
using Tiku.Domain.Common;
|
||||
|
||||
namespace Tiku.Domain.Tenancy;
|
||||
@@ -6,16 +5,13 @@ namespace Tiku.Domain.Tenancy;
|
||||
public sealed class TenantMembership : AuditableTenantEntity
|
||||
{
|
||||
public Guid UserId { get; set; }
|
||||
public Guid? RoleTemplateId { get; set; }
|
||||
public TenantRole Role { get; set; } = TenantRole.Student;
|
||||
public MembershipStatus Status { get; set; } = MembershipStatus.Active;
|
||||
public JsonElement Permissions { get; set; } = JsonDefaults.Object();
|
||||
public string? LegacyRole { get; set; }
|
||||
}
|
||||
|
||||
public enum TenantRole
|
||||
{
|
||||
PlatformAdmin,
|
||||
TenantOwner,
|
||||
TenantAdmin,
|
||||
TenantOperator,
|
||||
|
||||
@@ -47,9 +47,9 @@ public sealed class SmsVerificationCode : Entity, ITenantOwned
|
||||
public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow;
|
||||
}
|
||||
|
||||
public sealed class AuthLoginEvent : Entity, ITenantOwned
|
||||
public sealed class AuthLoginEvent : Entity
|
||||
{
|
||||
public Guid TenantId { get; set; }
|
||||
public Guid? TenantId { get; set; }
|
||||
public Guid? UserId { get; set; }
|
||||
public string Provider { get; set; } = string.Empty;
|
||||
public string? Identifier { get; set; }
|
||||
@@ -61,18 +61,46 @@ public sealed class AuthLoginEvent : Entity, ITenantOwned
|
||||
public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow;
|
||||
}
|
||||
|
||||
public sealed class AuthSession : AuditableTenantEntity
|
||||
public sealed class AuthSession : AuditableEntity
|
||||
{
|
||||
public AuthRealm Realm { get; set; } = AuthRealm.Tenant;
|
||||
public Guid? TenantId { get; set; }
|
||||
public Guid UserId { get; set; }
|
||||
public Guid TokenFamilyId { get; set; }
|
||||
public Guid? ParentSessionId { get; set; }
|
||||
public Guid? ReplacedBySessionId { get; set; }
|
||||
public string TokenHash { get; set; } = string.Empty;
|
||||
public string SecurityStamp { get; set; } = string.Empty;
|
||||
public bool MfaSatisfied { get; set; }
|
||||
public string Provider { get; set; } = string.Empty;
|
||||
public DateTimeOffset ExpiresAt { get; set; }
|
||||
public DateTimeOffset? RevokedAt { get; set; }
|
||||
public string? RevokedReason { get; set; }
|
||||
public string? IpAddress { get; set; }
|
||||
public string? UserAgent { get; set; }
|
||||
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
|
||||
}
|
||||
|
||||
public enum AuthRealm { Tenant, Platform }
|
||||
|
||||
public sealed class AuthChallenge : Entity
|
||||
{
|
||||
public Guid UserId { get; set; }
|
||||
public AuthRealm Realm { get; set; }
|
||||
public Guid? TenantId { get; set; }
|
||||
public AuthChallengePurpose Purpose { get; set; }
|
||||
public string TokenHash { get; set; } = string.Empty;
|
||||
public string SecurityStamp { get; set; } = string.Empty;
|
||||
public string Provider { get; set; } = string.Empty;
|
||||
public DateTimeOffset ExpiresAt { get; set; }
|
||||
public DateTimeOffset? ConsumedAt { get; set; }
|
||||
public string? IpAddress { get; set; }
|
||||
public string? UserAgent { get; set; }
|
||||
public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow;
|
||||
}
|
||||
|
||||
public enum AuthChallengePurpose { MfaEnrollment, MfaVerification, PasswordChange }
|
||||
|
||||
public sealed class SmsSendRateLimit : ITenantOwned
|
||||
{
|
||||
public Guid TenantId { get; set; }
|
||||
@@ -83,24 +111,6 @@ public sealed class SmsSendRateLimit : ITenantOwned
|
||||
public DateTimeOffset UpdatedAt { get; set; } = DateTimeOffset.UtcNow;
|
||||
}
|
||||
|
||||
public sealed class TenantRoleTemplate : AuditableTenantEntity
|
||||
{
|
||||
public string Code { get; set; } = string.Empty;
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string? Description { get; set; }
|
||||
public TenantRole BaseRole { get; set; } = TenantRole.TenantOperator;
|
||||
public TenantRoleTemplateStatus Status { get; set; } = TenantRoleTemplateStatus.Active;
|
||||
public JsonElement Permissions { get; set; } = JsonDefaults.Object();
|
||||
public JsonElement MenuPermissions { get; set; } = JsonDefaults.Object();
|
||||
public JsonElement ModulePermissions { get; set; } = JsonDefaults.Object();
|
||||
public JsonElement FieldPermissions { get; set; } = JsonDefaults.Object();
|
||||
public JsonElement DataScope { get; set; } = JsonDefaults.Object();
|
||||
public bool IsSystem { get; set; }
|
||||
public int SortOrder { get; set; } = 100;
|
||||
public Guid? CreatedBy { get; set; }
|
||||
public Guid? UpdatedBy { get; set; }
|
||||
}
|
||||
|
||||
public sealed class TenantClass : AuditableTenantEntity
|
||||
{
|
||||
public Guid? RegionId { get; set; }
|
||||
@@ -165,7 +175,6 @@ public enum SmsPurpose { Login, BindPhone, ResetPassword }
|
||||
public enum SmsVerificationStatus { Pending, Sent, Verified, Expired, Blocked, Failed }
|
||||
public enum AuthLoginResult { Sent, Success, Failed, Blocked }
|
||||
public enum SmsRateLimitDimension { Tenant, Phone, Ip, Device }
|
||||
public enum TenantRoleTemplateStatus { Active, Disabled, Archived }
|
||||
public enum TenantRecordStatus { Active, Disabled, Archived }
|
||||
public enum TenantClassMemberType { Student, Teacher, Assistant, HeadTeacher }
|
||||
public enum TenantClassMemberStatus { Active, Disabled, Removed }
|
||||
|
||||
@@ -6,4 +6,8 @@
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Identity.Stores" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
Reference in New Issue
Block a user