Where can I add a logging scope for permission requirements without repeating myself?

46 Views Asked by At

In .NET 6, I have added an authorization policy that ensures users have access to a certain set of resources. Now I want to log the ID of the set of resources as well as the User ID to show which user accessed or modified which set of resources. Not all of my endpoints need this logging scope, only those that have the policy requirement (routes with [Authorize(Policy = "MyResourcePolicyName")]).

I imagine there must be one place I can put this code so I don't have to add this logging scope at every endpoint. Where would I do this? The AuthorizationHandler.HandleRequirementAsync(ctx, requirement) doesn't seem like the correct place as there is not a next() call to make with a scoped wrapped around it. Is there another layer to add a logging scope to? Or something I can do at a middleware level that knows when the requirement is applied?

1

There are 1 best solutions below

0
On

I believe I figured out a solution. Place a middleware function after app.UseAuthorization() and before app.UseEndpoints(). This middleware can inspect the metadata of the endpoint to determine the applied policy and push context onto the logger.

public async Task Invoke(HttpContext context)
{
    // Check if the request requires authorization (you can customize this logic)
    var metadata = context.GetEndpoint()?.Metadata.GetMetadata<Microsoft.AspNetCore.Authorization.IAuthorizeData>();

    if (metadata != null && metadata.Policy == "MyPolicyName")
    {
        string userId = context.User.Claims.First(c => c.Type == ClaimTypes.NameIdentifier).Value;

        using (LogContext.PushProperty("UserId", userId))
        using (LogContext.PushProperty("ResourceSetId", context.Request.Headers["ResourceSet"]))
        {
            await _next(context);
        }
    }
    else
    {
        // Continue without pushing properties
        await _next(context);
    }
}