I have a Web API project that has a number of endpoints that are protected using an API key. To achieve this I have written some middleware to handle checking the header for the API key and validating it. This middleware is configured in the Startup.cs
app.UseMiddleware<ApiKeyMiddleware>();
This works perfectly, however I now have the requirement to have one endpoint that does not require any authorisation so it can be viewed in browser. I was hoping this would be done by using the AllowAnonymous attribute, however the middleware still checks for the API key.
I can achieve what I want by removing the middleware and making the API key check into an attribute, but is there a better way to do this?
EDIT:
This is the API key middleware implementation.
public class ApiKeyMiddleware
{
    private readonly RequestDelegate _next;
    private const string API_KEY_HEADER = "z-api-key";
    
    public ApiKeyMiddleware(RequestDelegate next)
    {
        _next = next;
    }
    
    public async Task InvokeAsync(HttpContext context)
    {
        if (!context.Request.Headers.TryGetValue(API_KEY_HEADER, out var extractedApiKey))
        {
            context.Response.StatusCode = 401;
            await context.Response.WriteAsync($"Api Key was not found in request. Please pass key in {API_KEY_HEADEr} header.");
            return;
        }
        var appSettings = context.RequestServices.GetRequiredService<IConfiguration>();
        var validApiKey = appSettings.GetValue<string>(API_KEY_HEADER);
        if (validApiKey != extractedApiKey)
        {
            context.Response.StatusCode = 401;
            await context.Response.WriteAsync("Invalid api key.");
            return;
        }
        await _next(context);
    }
}
                you can use HttpContext object to access endpoint and metadata like attributes.
var endpoint = context.GetEndpoint();
var isAllowAnonymous = endpoint?.Metadata.Any(x => x.GetType() == typeof(AllowAnonymousAttribute));
then add a conditional in your check to skip.
if (isAllowAnonymous == true)
{
    await _next(context);
    return;
}
Note: you should place your middleware after Routing middleware to use GetEndpoint extension method. if your middleware place before Routing middleware
GetEndpoint extension method return null
app.UseRouting();
app.UseMiddleware<ApiKeyMiddleware>();
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With