Add JWT auth, token service & Neutrino endpoint

This commit is contained in:
Holden
2026-06-19 12:25:45 -05:00
parent 608def3ac8
commit 3eebfc9ba2
27 changed files with 581 additions and 51 deletions

View File

@@ -0,0 +1,19 @@
using System.Security.Claims;
namespace RecNet.Application.Common.Security;
public static class ClaimsPrincipalExtensions
{
public static Guid GetProfileId(this ClaimsPrincipal user)
{
var value =
user.FindFirst("sub")?.Value ??
user.FindFirst(ClaimTypes.NameIdentifier)?.Value;
if (!Guid.TryParse(value, out var profileId))
throw new UnauthorizedAccessException(
"Account id claim is missing or invalid.");
return profileId;
}
}

View File

@@ -1,5 +1,4 @@
using Microsoft.Extensions.DependencyInjection;
using RecNet.Application.Services.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace RecNet.Application;
@@ -9,8 +8,9 @@ public static class DependencyInjection
{
services.AddAutoMapper(_ => { }, typeof(DependencyInjection).Assembly);
services.AddScoped<IConfigService, ConfigService>();
// Usually there would be CQRS, but I'm rushing out this server, so I didn't feel like adding it.
// Enjoy a VERY barebones application layer :D
return services;
}
}
}

View File

@@ -1,5 +1,4 @@
using System.Text.Json.Serialization;
using RecNet.Domain.Common;
namespace RecNet.Application.Profiles;
@@ -10,11 +9,4 @@ public class ProfileDTO
[JsonPropertyName("Name")]
public required string Name { get; init; }
[JsonPropertyName("Platform")]
public PlatformType Platform { get; init; }
[JsonPropertyName("CreatedAt")]
public DateTimeOffset CreatedAt { get; init; }
}

View File

@@ -1,33 +0,0 @@
using System.Text.Json;
using RecNet.Domain.Repositories;
namespace RecNet.Application.Services.Configuration;
public class ConfigService(IServerConfigRepository repository) : IConfigService
{
private static readonly JsonSerializerOptions JsonOptions = new(JsonSerializerDefaults.Web);
public async Task<T?> GetAsync<T>(
string key,
T? defaultValue = default,
CancellationToken ct = default)
{
var config = await repository.GetAsync(key, ct);
if (config == null)
return defaultValue;
return JsonSerializer.Deserialize<T>(config.Value, JsonOptions);
}
public async Task SetAsync<T>(
string key,
T value,
CancellationToken ct = default)
{
var json = JsonSerializer.Serialize(value, JsonOptions);
await repository.SetAsync(key, json, ct);
await repository.SaveChangesAsync(ct);
}
}

View File

@@ -1,7 +0,0 @@
namespace RecNet.Application.Services.Configuration;
public interface IConfigService
{
Task<T?> GetAsync<T>(string key, T? defaultValue = default, CancellationToken ct = default);
Task SetAsync<T>(string key, T value, CancellationToken ct = default);
}