mirror of
https://github.com/CyberL1/Minecraft-Realms-Emulator.git
synced 2026-09-15 19:25:48 -04:00
feat(core): add jwt validation to Authorization middleware
This commit is contained in:
@@ -12,6 +12,7 @@
|
|||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.19.1"/>
|
||||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.2"/>
|
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.2"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,23 @@
|
|||||||
|
using System.Security.Cryptography;
|
||||||
using Core.Models;
|
using Core.Models;
|
||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
|
using Microsoft.IdentityModel.JsonWebTokens;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
|
||||||
namespace Core.Middlewares;
|
namespace Core.Middlewares;
|
||||||
|
|
||||||
public class AuthorizationMiddleware(RequestDelegate next)
|
public class AuthorizationMiddleware(RequestDelegate next, IServiceProvider serviceProvider)
|
||||||
{
|
{
|
||||||
public Task Invoke(HttpContext httpContext, CookiePlayerData playerData)
|
public async Task Invoke(HttpContext httpContext, CookiePlayerData playerData)
|
||||||
{
|
{
|
||||||
var cookieHeader = httpContext.Request.Headers.Cookie.ToString();
|
var cookieHeader = httpContext.Request.Headers.Cookie.ToString();
|
||||||
|
|
||||||
if (cookieHeader.Trim() == "")
|
if (cookieHeader.Trim() == "")
|
||||||
{
|
{
|
||||||
httpContext.Response.StatusCode = 401;
|
httpContext.Response.StatusCode = 401;
|
||||||
return Task.CompletedTask;
|
await Task.CompletedTask;
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var hasSid = httpContext.Request.Cookies.ContainsKey("sid");
|
var hasSid = httpContext.Request.Cookies.ContainsKey("sid");
|
||||||
@@ -21,13 +27,66 @@ public class AuthorizationMiddleware(RequestDelegate next)
|
|||||||
if (!(hasSid && hasUser && hasVersion))
|
if (!(hasSid && hasUser && hasVersion))
|
||||||
{
|
{
|
||||||
httpContext.Response.StatusCode = 401;
|
httpContext.Response.StatusCode = 401;
|
||||||
return Task.CompletedTask;
|
await Task.CompletedTask;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var token = new JsonWebToken(httpContext.Request.Cookies["sid"]!.Split(":")[1]);
|
||||||
|
var memoryCache = serviceProvider.GetRequiredService<IMemoryCache>();
|
||||||
|
|
||||||
|
var validationParameters = new TokenValidationParameters
|
||||||
|
{
|
||||||
|
ValidateAudience = false,
|
||||||
|
ValidateLifetime = true,
|
||||||
|
ValidateActor = true,
|
||||||
|
ValidateIssuer = true,
|
||||||
|
ValidateIssuerSigningKey = true,
|
||||||
|
ValidIssuer = "authentication",
|
||||||
|
IssuerSigningKeyResolver = (_, _, _, _) =>
|
||||||
|
{
|
||||||
|
return memoryCache.GetOrCreate("minecraftPublicKeys", entry =>
|
||||||
|
{
|
||||||
|
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromDays(1);
|
||||||
|
|
||||||
|
var minecraftPublicKeys = new HttpClient()
|
||||||
|
.GetFromJsonAsync<MinecraftPublicKeys>("https://api.minecraftservices.com/publickeys")
|
||||||
|
.GetAwaiter()
|
||||||
|
.GetResult();
|
||||||
|
|
||||||
|
var signingKeys = new List<SecurityKey>();
|
||||||
|
|
||||||
|
if (minecraftPublicKeys == null)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Couldn't fetch Minecraft Public Keys");
|
||||||
|
return signingKeys;
|
||||||
|
}
|
||||||
|
|
||||||
|
var publicKeyBytes = Convert.FromBase64String(minecraftPublicKeys.AuthenticationKeys[0].PublicKey);
|
||||||
|
var rsa = RSA.Create();
|
||||||
|
|
||||||
|
rsa.ImportSubjectPublicKeyInfo(publicKeyBytes, out _);
|
||||||
|
signingKeys.Add(new RsaSecurityKey(rsa.ExportParameters(false)));
|
||||||
|
|
||||||
|
return signingKeys;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var validationResult = await new JsonWebTokenHandler().ValidateTokenAsync(token, validationParameters);
|
||||||
|
|
||||||
|
if (!validationResult.IsValid)
|
||||||
|
{
|
||||||
|
httpContext.Response.StatusCode = 401;
|
||||||
|
await Task.CompletedTask;
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
playerData.Uuid = httpContext.Request.Cookies["sid"]!.Split(":")[2];
|
playerData.Uuid = httpContext.Request.Cookies["sid"]!.Split(":")[2];
|
||||||
playerData.Name = httpContext.Request.Cookies["user"]!;
|
playerData.Name = httpContext.Request.Cookies["user"]!;
|
||||||
playerData.Version = httpContext.Request.Cookies["version"]!;
|
playerData.Version = httpContext.Request.Cookies["version"]!;
|
||||||
|
|
||||||
return next(httpContext);
|
await next(httpContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
namespace Core.Models;
|
||||||
|
|
||||||
|
public class MinecraftPublicKeys
|
||||||
|
{
|
||||||
|
public required List<PublicKeyWrapper> ProfilePropertyKeys { get; set; }
|
||||||
|
public required List<PublicKeyWrapper> PlayerCertificateKeys { get; set; }
|
||||||
|
public required List<PublicKeyWrapper> AuthenticationKeys { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PublicKeyWrapper
|
||||||
|
{
|
||||||
|
public required string PublicKey { get; set; }
|
||||||
|
}
|
||||||
+2
-1
@@ -8,6 +8,7 @@ var builder = WebApplication.CreateBuilder(args);
|
|||||||
|
|
||||||
builder.Services.AddScoped<CookiePlayerData>();
|
builder.Services.AddScoped<CookiePlayerData>();
|
||||||
|
|
||||||
|
builder.Services.AddMemoryCache();
|
||||||
builder.Services.AddControllers();
|
builder.Services.AddControllers();
|
||||||
|
|
||||||
var connectionString = builder.Configuration.GetValue<string>("Database");
|
var connectionString = builder.Configuration.GetValue<string>("Database");
|
||||||
@@ -32,7 +33,7 @@ if (!app.Environment.IsDevelopment())
|
|||||||
|
|
||||||
app.UseRouting();
|
app.UseRouting();
|
||||||
|
|
||||||
app.UseMiddleware<AuthorizationMiddleware>();
|
app.UseMiddleware<AuthorizationMiddleware>(app.Services);
|
||||||
app.UseMiddleware<CheckRealmAccessMiddleware>();
|
app.UseMiddleware<CheckRealmAccessMiddleware>();
|
||||||
|
|
||||||
app.MapControllers();
|
app.MapControllers();
|
||||||
|
|||||||
Reference in New Issue
Block a user