♻️ Refactored to make a simplifier auth session system

This commit is contained in:
2025-12-03 00:38:28 +08:00
parent 74c8f3490d
commit 270c211cb8
18 changed files with 3130 additions and 130 deletions

View File

@@ -60,7 +60,7 @@ public class DysonTokenAuthHandler(
};
// Add scopes as claims
session.Challenge?.Scopes.ToList().ForEach(scope => claims.Add(new Claim("scope", scope)));
session.Scopes.ToList().ForEach(scope => claims.Add(new Claim("scope", scope)));
// Add superuser claim if applicable
if (session.Account.IsSuperuser)

View File

@@ -22,7 +22,8 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="MaxMind.GeoIP2" Version="5.3.0" />
<PackageReference Include="MessagePack" Version="2.5.192" />
<PackageReference Include="MessagePack" Version="3.1.4" />
<PackageReference Include="MessagePack.NodaTime" Version="3.5.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication" Version="2.3.0" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.0" />
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="10.0.0" />

View File

@@ -70,7 +70,7 @@ public static class Extensions
return RedLockFactory.Create(new List<RedLockMultiplexer> { new(mux) });
});
builder.Services.AddSingleton<ICacheService, CacheServiceRedis>();
builder.Services.AddSingleton<ICacheSerializer, JsonCacheSerializer>();
builder.Services.AddSingleton<ICacheSerializer, MessagePackCacheSerializer>();
return builder;
}

View File

@@ -2,24 +2,34 @@ using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json.Serialization;
using DysonNetwork.Shared.GeoIp;
using DysonNetwork.Shared.Proto;
using NodaTime;
using NodaTime.Serialization.Protobuf;
namespace DysonNetwork.Shared.Models;
public enum SessionType
{
Login,
OAuth, // Trying to authorize other platforms
Oidc // Trying to connect other platforms
}
public class SnAuthSession : ModelBase
{
public Guid Id { get; set; } = Guid.NewGuid();
public SessionType Type { get; set; } = SessionType.Login;
public Instant? LastGrantedAt { get; set; }
public Instant? ExpiredAt { get; set; }
[Column(TypeName = "jsonb")] public List<string> Audiences { get; set; } = [];
[Column(TypeName = "jsonb")] public List<string> Scopes { get; set; } = [];
[MaxLength(128)] public string? IpAddress { get; set; }
[MaxLength(512)] public string? UserAgent { get; set; }
public Guid AccountId { get; set; }
[JsonIgnore] public SnAccount Account { get; set; } = null!;
// The challenge that created this session
public Guid? ChallengeId { get; set; }
public SnAuthChallenge? Challenge { get; set; } = null!;
// The client device for this session
public Guid? ClientId { get; set; }
public SnAuthClient? Client { get; set; } = null!;
@@ -28,30 +38,41 @@ public class SnAuthSession : ModelBase
public Guid? ParentSessionId { get; set; }
public SnAuthSession? ParentSession { get; set; }
// The origin challenge for this session
public Guid? ChallengeId { get; set; }
// Indicates the session is for an OIDC connection
public Guid? AppId { get; set; }
public Proto.AuthSession ToProtoValue() => new()
public AuthSession ToProtoValue()
{
Id = Id.ToString(),
LastGrantedAt = LastGrantedAt?.ToTimestamp(),
ExpiredAt = ExpiredAt?.ToTimestamp(),
AccountId = AccountId.ToString(),
Account = Account.ToProtoValue(),
ChallengeId = ChallengeId.ToString(),
Challenge = Challenge?.ToProtoValue(),
ClientId = ClientId.ToString(),
Client = Client?.ToProtoValue(),
ParentSessionId = ParentSessionId.ToString(),
AppId = AppId?.ToString()
};
}
var proto = new AuthSession
{
Id = Id.ToString(),
LastGrantedAt = LastGrantedAt?.ToTimestamp(),
Type = Type switch
{
SessionType.Login => Proto.SessionType.Login,
SessionType.OAuth => Proto.SessionType.Oauth,
SessionType.Oidc => Proto.SessionType.Oidc,
_ => Proto.SessionType.ChallengeTypeUnspecified
},
IpAddress = IpAddress,
UserAgent = UserAgent,
ExpiredAt = ExpiredAt?.ToTimestamp(),
AccountId = AccountId.ToString(),
Account = Account.ToProtoValue(),
ClientId = ClientId.ToString(),
Client = Client?.ToProtoValue(),
ParentSessionId = ParentSessionId.ToString(),
AppId = AppId?.ToString()
};
proto.Audiences.AddRange(Audiences);
proto.Scopes.AddRange(Scopes);
public enum ChallengeType
{
Login,
OAuth, // Trying to authorize other platforms
Oidc // Trying to connect other platforms
return proto;
}
}
public enum ClientPlatform
@@ -72,10 +93,9 @@ public class SnAuthChallenge : ModelBase
public int StepRemain { get; set; }
public int StepTotal { get; set; }
public int FailedAttempts { get; set; }
public ChallengeType Type { get; set; } = ChallengeType.Login;
[Column(TypeName = "jsonb")] public List<Guid> BlacklistFactors { get; set; } = new();
[Column(TypeName = "jsonb")] public List<string> Audiences { get; set; } = new();
[Column(TypeName = "jsonb")] public List<string> Scopes { get; set; } = new();
[Column(TypeName = "jsonb")] public List<Guid> BlacklistFactors { get; set; } = [];
[Column(TypeName = "jsonb")] public List<string> Audiences { get; set; } = [];
[Column(TypeName = "jsonb")] public List<string> Scopes { get; set; } = [];
[MaxLength(128)] public string? IpAddress { get; set; }
[MaxLength(512)] public string? UserAgent { get; set; }
[MaxLength(512)] public string DeviceId { get; set; } = null!;
@@ -93,14 +113,13 @@ public class SnAuthChallenge : ModelBase
return this;
}
public Proto.AuthChallenge ToProtoValue() => new()
public AuthChallenge ToProtoValue() => new()
{
Id = Id.ToString(),
ExpiredAt = ExpiredAt?.ToTimestamp(),
StepRemain = StepRemain,
StepTotal = StepTotal,
FailedAttempts = FailedAttempts,
Type = (Proto.ChallengeType)Type,
BlacklistFactors = { BlacklistFactors.Select(x => x.ToString()) },
Audiences = { Audiences },
Scopes = { Scopes },
@@ -150,4 +169,4 @@ public class SnAuthClientWithChallenge : SnAuthClient
AccountId = client.AccountId,
};
}
}
}

View File

@@ -17,12 +17,15 @@ message AuthSession {
optional google.protobuf.Timestamp expired_at = 4;
string account_id = 5;
Account account = 6;
string challenge_id = 7;
AuthChallenge challenge = 8;
google.protobuf.StringValue app_id = 9;
optional string client_id = 10;
optional string parent_session_id = 11;
AuthClient client = 12;
repeated string audiences = 13;
repeated string scopes = 14;
google.protobuf.StringValue ip_address = 15;
google.protobuf.StringValue user_agent = 16;
SessionType type = 17;
}
// Represents an authentication challenge
@@ -32,7 +35,6 @@ message AuthChallenge {
int32 step_remain = 3;
int32 step_total = 4;
int32 failed_attempts = 5;
ChallengeType type = 7;
repeated string blacklist_factors = 8;
repeated string audiences = 9;
repeated string scopes = 10;
@@ -56,7 +58,7 @@ message AuthClient {
}
// Enum for challenge types
enum ChallengeType {
enum SessionType {
CHALLENGE_TYPE_UNSPECIFIED = 0;
LOGIN = 1;
OAUTH = 2;