Move APIKeys to file and allow read vs read/write

This commit is contained in:
2023-11-23 11:41:58 -05:00
parent 15f8385005
commit a7045ea9a4
12 changed files with 100 additions and 17 deletions

View File

@@ -3,7 +3,7 @@ using Microsoft.AspNetCore.Mvc.Filters;
namespace TodoApi.Helpers;
public class ApiKeyAttribute : ActionFilterAttribute
public class ApiKeyCanReadAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
@@ -14,7 +14,7 @@ public class ApiKeyAttribute : ActionFilterAttribute
var apiKey = context.HttpContext.Request.Headers["X-API-KEY"];
// Validate the API key using the IApiKeyValidator service
if (string.IsNullOrEmpty(apiKey) || !apiKeyValidator.Validate(apiKey))
if (string.IsNullOrEmpty(apiKey) || !apiKeyValidator.CanRead(apiKey))
{
// If the API key is invalid, set the response status code to 401 Unauthorized
context.Result = new UnauthorizedResult();

View File

@@ -0,0 +1,27 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
namespace TodoApi.Helpers;
public class ApiKeyCanWriteAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
// Get the required service to validate the API key
var apiKeyValidator = context.HttpContext.RequestServices.GetRequiredService<IApiKeyValidator>();
// Get the API key from the X-API-KEY header
var apiKey = context.HttpContext.Request.Headers["X-API-KEY"];
// Validate the API key using the IApiKeyValidator service
if (string.IsNullOrEmpty(apiKey) || !apiKeyValidator.CanWrite(apiKey))
{
// If the API key is invalid, set the response status code to 401 Unauthorized
context.Result = new UnauthorizedResult();
return;
}
// If the API key is valid, continue with the action execution
base.OnActionExecuting(context);
}
}

View File

@@ -2,19 +2,29 @@ namespace TodoApi.Helpers
{
public interface IApiKeyValidator
{
bool Validate(string? apiKey);
bool CanRead(string? apiKey);
bool CanWrite(string? apiKey);
}
public class ApiKeyValidator(List<string>? apiKeys) : IApiKeyValidator
public class ApiKeyValidator(ApiKeys? apiKeys) : IApiKeyValidator
{
private readonly List<string>? _apiKeys = apiKeys;
private readonly ApiKeys _apiKeys = apiKeys ?? new ApiKeys();
public bool Validate(string? apiKey)
public bool CanRead(string? apiKey)
{
if (_apiKeys == null) return false;
if (apiKey == null) return false;
// Verify the provided apiKey is in our configuration
return _apiKeys.Contains(apiKey!.ToLower());
return _apiKeys.ReadOnly.Contains(apiKey, StringComparison.OrdinalIgnoreCase) ||
_apiKeys.ReadWrite.Contains(apiKey, StringComparison.OrdinalIgnoreCase);
}
public bool CanWrite(string? apiKey)
{
if (apiKey == null) return false;
// Verify the provided apiKey is in our configuration
return _apiKeys.ReadWrite.Contains(apiKey, StringComparison.OrdinalIgnoreCase);
}
}
}

12
Helpers/ApiKeys.cs Normal file
View File

@@ -0,0 +1,12 @@
using Newtonsoft.Json;
namespace TodoApi.Helpers;
public class ApiKeys
{
[JsonProperty("read_only")]
public List<string> ReadOnly { get; set; } = [];
[JsonProperty("read_write")]
public List<string> ReadWrite { get; set; } = [];
}

View File

@@ -0,0 +1,12 @@
namespace TodoApi;
public static class ExtensionMethods
{
public static bool Contains(this IEnumerable<string> source, string toCheck, StringComparison comp)
{
return
source != null &&
!string.IsNullOrEmpty(toCheck) &&
source.Any(x => string.Compare(x, toCheck, comp) == 0);
}
}