added api key auth docs #7
| @@ -36,6 +36,7 @@ export default defineConfig({ | ||||
|           { text: 'Google Sign in without Identity', link: '/dotnet/google-sign-in-without-identity' }, | ||||
|           { text: 'Service Testing', link: '/dotnet/service-testing' }, | ||||
|           { text: 'Controller Testing', link: '/dotnet/controller-testing' }, | ||||
|           { text: 'API Key Authentication', link: '/dotnet/api-key-auth'} | ||||
|         ] | ||||
|       }, | ||||
|       { | ||||
|   | ||||
							
								
								
									
										136
									
								
								docs/dotnet/api-key-auth.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								docs/dotnet/api-key-auth.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,136 @@ | ||||
| # API Key Auth | ||||
|  | ||||
| Simple API Key authentication is a great option when building public facing APIs without strict security requirements, but you would rather not leave open. Think syncs, long running jobs or other non-critical operations. | ||||
|  | ||||
| ## Configuration | ||||
|  | ||||
| This example stores the ApiKey in the `appsettings.json` file. You can also store it in a database, environment variable, or any other configuration source. | ||||
|  | ||||
| ::: code-group | ||||
|  | ||||
| ```json[appsettings.json] | ||||
| { | ||||
|   "Logging": { | ||||
|     "LogLevel": { | ||||
|       "Default": "Information", | ||||
|       "Microsoft.AspNetCore": "Warning" | ||||
|     } | ||||
|   }, | ||||
|   "AllowedHosts": "*", | ||||
|   "ApiKey": "ThisIsMySecretKey", | ||||
|   // ... | ||||
| } | ||||
| ``` | ||||
|  | ||||
| ::: | ||||
|  | ||||
| ## Filter | ||||
|  | ||||
| The logic for the api key authentication is a simple Authorization filter. It checks the `ApiKey` header against the configured value.  | ||||
|  | ||||
| Start by storing the header name in a constants file or similar: | ||||
|  | ||||
| ::: code-group | ||||
|  | ||||
| ```csharp[Constants.cs] | ||||
| namespace ApiKeyAuthDemo.Core | ||||
| { | ||||
|     public static class Constants | ||||
|     { | ||||
|         public const string API_KEY_HEADER_NAME = "X-API-KEY"; | ||||
|     } | ||||
| } | ||||
| ``` | ||||
|  | ||||
| ::: | ||||
|  | ||||
| Then create the filter: | ||||
|  | ||||
| ::: code-group | ||||
|  | ||||
| ```csharp[ApiKeyAuthorizeAttribute.cs] | ||||
| using Microsoft.AspNetCore.Mvc; | ||||
| using Microsoft.AspNetCore.Mvc.Filters; | ||||
|  | ||||
| namespace ApiKeyAuthDemo.Core.Filters | ||||
| { | ||||
|     [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] | ||||
|     public class ApiKeyAuthorizeAttribute() : Attribute, IAuthorizationFilter | ||||
|     { | ||||
|         public void OnAuthorization(AuthorizationFilterContext context) | ||||
|         { | ||||
|             // Get the API key from the request headers | ||||
|             string? apiKeyValue = context.HttpContext.Request.Headers[Constants.API_KEY_HEADER_NAME]; | ||||
|  | ||||
|             // Get the API key from the configuration | ||||
|             IConfiguration configuration = context.HttpContext.RequestServices.GetRequiredService<IConfiguration>(); | ||||
|             string? apiKey = configuration.GetValue<string>("ApiKey"); | ||||
|  | ||||
|             // Check if the API key is valid and set | ||||
|             if (apiKeyValue == null || apiKeyValue != apiKey) | ||||
|             { | ||||
|                 context.Result = new UnauthorizedResult(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| ``` | ||||
|  | ||||
| ::: | ||||
|  | ||||
| ## Usage | ||||
|  | ||||
| See below for example usage (on the second GET method): | ||||
|  | ||||
| ::: code-group | ||||
|  | ||||
| ```csharp[WeatherForecastController.cs] | ||||
| using ApiKeyAuthDemo.Core.Filters; | ||||
| using Microsoft.AspNetCore.Mvc; | ||||
|  | ||||
| namespace ApiKeyAuthDemo.Controllers; | ||||
|  | ||||
| [ApiController] | ||||
| [Route("[controller]")] | ||||
| public class WeatherForecastController : ControllerBase | ||||
| { | ||||
|     private static readonly string[] Summaries = new[] | ||||
|     { | ||||
|         "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" | ||||
|     }; | ||||
|  | ||||
|     private readonly ILogger<WeatherForecastController> _logger; | ||||
|  | ||||
|     public WeatherForecastController(ILogger<WeatherForecastController> logger) | ||||
|     { | ||||
|         _logger = logger; | ||||
|     } | ||||
|  | ||||
|     [HttpGet] | ||||
|     public IEnumerable<WeatherForecast> Get() | ||||
|     { | ||||
|         return Enumerable.Range(1, 5).Select(index => new WeatherForecast | ||||
|         { | ||||
|             Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)), | ||||
|             TemperatureC = Random.Shared.Next(-20, 55), | ||||
|             Summary = Summaries[Random.Shared.Next(Summaries.Length)] | ||||
|         }) | ||||
|         .ToArray(); | ||||
|     } | ||||
|  | ||||
|     [ApiKeyAuthorize] | ||||
|     [HttpGet("auth")] | ||||
|     public IEnumerable<WeatherForecast> GetAuth() | ||||
|     { | ||||
|         return Enumerable.Range(1, 5).Select(index => new WeatherForecast | ||||
|         { | ||||
|             Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)), | ||||
|             TemperatureC = Random.Shared.Next(-20, 55), | ||||
|             Summary = Summaries[Random.Shared.Next(Summaries.Length)] | ||||
|         }) | ||||
|         .ToArray(); | ||||
|     } | ||||
| } | ||||
| ``` | ||||
|  | ||||
| ::: | ||||
| @@ -12,3 +12,4 @@ | ||||
| #### [Google Sign in Without Identity](./google-sign-in-without-identity.md) | ||||
| #### [Service Testing](./service-testing.md) | ||||
| #### [Controller Testing](./controller-testing.md) | ||||
| #### [API Key Authentication](./api-key-auth.md) | ||||
		Reference in New Issue
	
	Block a user