Ryan Thomas
Ryan Thomas

Reputation: 2002

.NET Core Web API API Key Authentication AllowAnonymous

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);
    }
}

Upvotes: 4

Views: 2701

Answers (1)

Alirexaa
Alirexaa

Reputation: 156

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>();

Upvotes: 8

Related Questions