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: 'Google Sign in without Identity', link: '/dotnet/google-sign-in-without-identity' }, | ||||||
|           { text: 'Service Testing', link: '/dotnet/service-testing' }, |           { text: 'Service Testing', link: '/dotnet/service-testing' }, | ||||||
|           { text: 'Controller Testing', link: '/dotnet/controller-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(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ::: | ||||||
| @@ -11,4 +11,5 @@ | |||||||
| #### [JWT Authentication with Cookie](./jwt-authentication-cookie.md) | #### [JWT Authentication with Cookie](./jwt-authentication-cookie.md) | ||||||
| #### [Google Sign in Without Identity](./google-sign-in-without-identity.md) | #### [Google Sign in Without Identity](./google-sign-in-without-identity.md) | ||||||
| #### [Service Testing](./service-testing.md) | #### [Service Testing](./service-testing.md) | ||||||
| #### [Controller Testing](./controller-testing.md) | #### [Controller Testing](./controller-testing.md) | ||||||
|  | #### [API Key Authentication](./api-key-auth.md) | ||||||
		Reference in New Issue
	
	Block a user