fix(auth): MoySklad admin endpoint uses policy-based auth on role claim directly
ASP.NET Core's [Authorize(Roles=...)] relies on ClaimsIdentity.RoleClaimType to
match, which may not be wired to "role" in the OpenIddict validation handler's
identity (depending on middleware order with AddIdentity). Tokens clearly carry
"role": "Admin" but IsInRole("Admin") returns false.
- Register AddAuthorization policy "AdminAccess" that checks the `role` claim
explicitly (c.Type == Claims.Role && Value in {Admin, SuperAdmin}). Works
regardless of how ClaimsIdentity was constructed.
- MoySkladImportController now uses [Authorize(Policy = "AdminAccess")].
- Add /api/_debug/whoami that echoes authType, roleClaimType, claims, and
IsInRole result — makes next auth issue trivial to diagnose.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
b07232521b
commit
e4a2030ad9
|
|
@ -5,7 +5,7 @@
|
||||||
namespace foodmarket.Api.Controllers.Admin;
|
namespace foodmarket.Api.Controllers.Admin;
|
||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Authorize(Roles = "Admin,SuperAdmin")]
|
[Authorize(Policy = "AdminAccess")]
|
||||||
[Route("api/admin/moysklad")]
|
[Route("api/admin/moysklad")]
|
||||||
public class MoySkladImportController : ControllerBase
|
public class MoySkladImportController : ControllerBase
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -111,7 +111,13 @@
|
||||||
options.DefaultAuthenticateScheme = OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme;
|
options.DefaultAuthenticateScheme = OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme;
|
||||||
options.DefaultChallengeScheme = OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme;
|
options.DefaultChallengeScheme = OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme;
|
||||||
});
|
});
|
||||||
builder.Services.AddAuthorization();
|
builder.Services.AddAuthorization(opts =>
|
||||||
|
{
|
||||||
|
// Check the "role" claim explicitly — robust against role-claim-type mismatches between
|
||||||
|
// OpenIddict validation identity and the default ClaimTypes.Role uri.
|
||||||
|
opts.AddPolicy("AdminAccess", p => p.RequireAssertion(ctx =>
|
||||||
|
ctx.User.HasClaim(c => c.Type == Claims.Role && (c.Value == "Admin" || c.Value == "SuperAdmin"))));
|
||||||
|
});
|
||||||
|
|
||||||
builder.Services.AddControllers();
|
builder.Services.AddControllers();
|
||||||
builder.Services.AddEndpointsApiExplorer();
|
builder.Services.AddEndpointsApiExplorer();
|
||||||
|
|
@ -143,6 +149,21 @@
|
||||||
|
|
||||||
app.MapGet("/health", () => Results.Ok(new { status = "ok", time = DateTime.UtcNow }));
|
app.MapGet("/health", () => Results.Ok(new { status = "ok", time = DateTime.UtcNow }));
|
||||||
|
|
||||||
|
app.MapGet("/api/_debug/whoami", (HttpContext ctx) =>
|
||||||
|
{
|
||||||
|
var identity = ctx.User.Identity as System.Security.Claims.ClaimsIdentity;
|
||||||
|
return Results.Ok(new
|
||||||
|
{
|
||||||
|
isAuthenticated = ctx.User.Identity?.IsAuthenticated,
|
||||||
|
authType = ctx.User.Identity?.AuthenticationType,
|
||||||
|
nameClaimType = identity?.NameClaimType,
|
||||||
|
roleClaimType = identity?.RoleClaimType,
|
||||||
|
isInRoleAdmin = ctx.User.IsInRole("Admin"),
|
||||||
|
hasAdminRoleClaim = ctx.User.HasClaim(c => c.Type == Claims.Role && c.Value == "Admin"),
|
||||||
|
claims = ctx.User.Claims.Select(c => new { c.Type, c.Value }),
|
||||||
|
});
|
||||||
|
}).RequireAuthorization();
|
||||||
|
|
||||||
app.MapGet("/api/me", (HttpContext ctx) =>
|
app.MapGet("/api/me", (HttpContext ctx) =>
|
||||||
{
|
{
|
||||||
var user = ctx.User;
|
var user = ctx.User;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue