🐛 Fix some issues within auth perk

This commit is contained in:
2026-02-04 21:10:54 +08:00
parent b7de6eb68c
commit c1669286f4
2 changed files with 32 additions and 40 deletions

View File

@@ -2,6 +2,7 @@ using System.Security.Cryptography;
using System.Text; using System.Text;
using DysonNetwork.Shared.Cache; using DysonNetwork.Shared.Cache;
using DysonNetwork.Shared.Models; using DysonNetwork.Shared.Models;
using DysonNetwork.Shared.Registry;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using NodaTime; using NodaTime;
@@ -12,7 +13,8 @@ public class TokenAuthService(
IConfiguration config, IConfiguration config,
ICacheService cache, ICacheService cache,
ILogger<TokenAuthService> logger, ILogger<TokenAuthService> logger,
OidcProvider.Services.OidcProviderService oidc OidcProvider.Services.OidcProviderService oidc,
RemoteSubscriptionService subscriptions
) )
{ {
/// <summary> /// <summary>
@@ -32,7 +34,7 @@ public class TokenAuthService(
logger.LogWarning("AuthenticateTokenAsync: no token provided"); logger.LogWarning("AuthenticateTokenAsync: no token provided");
return (false, null, "No token provided."); return (false, null, "No token provided.");
} }
if (!string.IsNullOrEmpty(ipAddress)) if (!string.IsNullOrEmpty(ipAddress))
{ {
logger.LogDebug("AuthenticateTokenAsync: client IP: {IpAddress}", ipAddress); logger.LogDebug("AuthenticateTokenAsync: client IP: {IpAddress}", ipAddress);
@@ -95,6 +97,11 @@ public class TokenAuthService(
logger.LogWarning("AuthenticateTokenAsync: session not found (sessionId={SessionId})", sessionId); logger.LogWarning("AuthenticateTokenAsync: session not found (sessionId={SessionId})", sessionId);
return (false, null, "Session was not found."); return (false, null, "Session was not found.");
} }
else
{
var perkSub = await subscriptions.GetPerkSubscription(session.AccountId);
if (perkSub is not null) session.Account.PerkSubscription = SnWalletSubscription.FromProtoValue(perkSub!).ToReference();
}
var now = SystemClock.Instance.GetCurrentInstant(); var now = SystemClock.Instance.GetCurrentInstant();
if (session.ExpiredAt.HasValue && session.ExpiredAt < now) if (session.ExpiredAt.HasValue && session.ExpiredAt < now)
@@ -138,7 +145,7 @@ public class TokenAuthService(
return (false, null, "Authentication error."); return (false, null, "Authentication error.");
} }
} }
public bool ValidateToken(string token, out Guid sessionId) public bool ValidateToken(string token, out Guid sessionId)
{ {
sessionId = Guid.Empty; sessionId = Guid.Empty;
@@ -150,27 +157,27 @@ public class TokenAuthService(
switch (parts.Length) switch (parts.Length)
{ {
case 3: case 3:
{ {
// JWT via OIDC // JWT via OIDC
var (isValid, jwtResult) = oidc.ValidateToken(token); var (isValid, jwtResult) = oidc.ValidateToken(token);
if (!isValid) return false; if (!isValid) return false;
var jti = jwtResult?.Claims.FirstOrDefault(c => c.Type == "jti")?.Value; var jti = jwtResult?.Claims.FirstOrDefault(c => c.Type == "jti")?.Value;
if (jti is null) return false; if (jti is null) return false;
return Guid.TryParse(jti, out sessionId); return Guid.TryParse(jti, out sessionId);
} }
case 2: case 2:
{ {
// Compact token // Compact token
var payloadBytes = Base64UrlDecode(parts[0]); var payloadBytes = Base64UrlDecode(parts[0]);
sessionId = new Guid(payloadBytes); sessionId = new Guid(payloadBytes);
var publicKeyPem = File.ReadAllText(config["AuthToken:PublicKeyPath"]!); var publicKeyPem = File.ReadAllText(config["AuthToken:PublicKeyPath"]!);
using var rsa = RSA.Create(); using var rsa = RSA.Create();
rsa.ImportFromPem(publicKeyPem); rsa.ImportFromPem(publicKeyPem);
var signature = Base64UrlDecode(parts[1]); var signature = Base64UrlDecode(parts[1]);
return rsa.VerifyData(payloadBytes, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); return rsa.VerifyData(payloadBytes, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
} }
default: default:
return false; return false;
} }

View File

@@ -21,7 +21,7 @@ public class DysonTokenAuthHandler(
{ {
protected override async Task<AuthenticateResult> HandleAuthenticateAsync() protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{ {
var tokenInfo = _ExtractToken(Request); var tokenInfo = ExtractToken(Request);
if (tokenInfo == null || string.IsNullOrEmpty(tokenInfo.Token)) if (tokenInfo == null || string.IsNullOrEmpty(tokenInfo.Token))
return AuthenticateResult.Fail("No token was provided."); return AuthenticateResult.Fail("No token was provided.");
@@ -91,22 +91,7 @@ public class DysonTokenAuthHandler(
return resp.Session ?? throw new InvalidOperationException("Session not found."); return resp.Session ?? throw new InvalidOperationException("Session not found.");
} }
private static byte[] Base64UrlDecode(string base64Url) private static TokenInfo? ExtractToken(HttpRequest request)
{
var padded = base64Url
.Replace('-', '+')
.Replace('_', '/');
switch (padded.Length % 4)
{
case 2: padded += "=="; break;
case 3: padded += "="; break;
}
return Convert.FromBase64String(padded);
}
private static TokenInfo? _ExtractToken(HttpRequest request)
{ {
// Check for token in query parameters // Check for token in query parameters
if (request.Query.TryGetValue(AuthConstants.TokenQueryParamName, out var queryToken)) if (request.Query.TryGetValue(AuthConstants.TokenQueryParamName, out var queryToken))
@@ -120,7 +105,7 @@ public class DysonTokenAuthHandler(
// Check for token in Authorization header // Check for token in Authorization header
var authHeader = request.Headers["Authorization"].ToString(); var authHeader = request.Headers.Authorization.ToString();
if (!string.IsNullOrEmpty(authHeader)) if (!string.IsNullOrEmpty(authHeader))
{ {
if (authHeader.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase)) if (authHeader.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
@@ -165,4 +150,4 @@ public class DysonTokenAuthHandler(
return null; return null;
} }
} }