using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.EntityFrameworkCore;
using DorkNet.Server.Data;
namespace DorkNet.Server.Auth;
///
/// Action / controller filter that 403s any request whose
/// JWT-resolved player doesn't have IsAdmin == true. Does not
/// itself authenticate — pair it with [Authorize] to ensure a
/// valid bearer is present before this runs.
///
/// Usage:
///
/// [Authorize]
/// [AdminOnly]
/// [Route("api/admin/v1")]
/// public class AdminController { ... }
///
///
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
public class AdminOnlyAttribute : Attribute, IAsyncAuthorizationFilter
{
public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
{
// AuthorizationFilterContext.HttpContext is always populated and
// exposes the same ClaimsPrincipal a controller would see, so
// there's no reason to round-trip through IHttpContextAccessor
// (which isn't even registered in this app's DI container — the
// earlier lookup crashed every admin request with
// "No service for type IHttpContextAccessor has been registered").
if (ControllerBaseExtensions.CurrentPlayerId(context.HttpContext.User) is not long id)
{
// No JWT → defer to [Authorize]'s 401.
context.Result = new UnauthorizedResult();
return;
}
var db = context.HttpContext.RequestServices
.GetRequiredService();
var isAdmin = await db.Players
.Where(p => p.Id == id)
.Select(p => p.IsAdmin)
.FirstOrDefaultAsync();
if (!isAdmin)
context.Result = new ForbidResult();
}
}