using Microsoft.AspNetCore.Mvc;
using System.Security.Claims;
namespace DorkNet.Server.Auth;
///
/// Single canonical place for "who is the bearer-resolved player on this
/// request." Replaces the per-controller copy-paste of:
///
/// private long CurrentPlayerId =>
/// long.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier)!);
///
/// which historically existed in 10 controllers and silently NPE-bombed
/// the action when the bearer was missing instead of returning 401.
///
public static class ControllerBaseExtensions
{
///
/// Returns the bearer-resolved player id, or null when the caller is
/// anonymous / the bearer is malformed. Use on optional-auth endpoints.
///
public static long? CurrentPlayerId(this ControllerBase controller) =>
CurrentPlayerId(controller.User);
/// Overload for non-controller callers (filters,
/// middleware) that hold a directly.
public static long? CurrentPlayerId(ClaimsPrincipal user)
{
var claim = user.FindFirstValue(ClaimTypes.NameIdentifier);
return long.TryParse(claim, out var id) ? id : null;
}
///
/// Returns the bearer-resolved player id; throws
/// when missing. Use on
/// [Authorize]-decorated endpoints where a missing id is a
/// programming error (the framework should have already 401'd).
///
public static long RequireCurrentPlayerId(this ControllerBase controller) =>
controller.CurrentPlayerId()
?? throw new UnauthorizedAccessException(
"Bearer token claim 'NameIdentifier' is missing or non-numeric. " +
"If this fired on an [Authorize] endpoint, JWT validation upstream " +
"is misconfigured.");
}