using System; using System.Linq; using System.Text; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; namespace AMWD.Common.AspNetCore.BasicAuthentication { /// /// Implements a basic authentication. /// public class BasicAuthenticationMiddleware { private readonly RequestDelegate next; private readonly IBasicAuthenticationValidator validator; /// /// Initializes a new instance of the class. /// /// The following delegate in the process chain. /// A basic authentication validator. public BasicAuthenticationMiddleware(RequestDelegate next, IBasicAuthenticationValidator validator) { this.next = next; this.validator = validator; } /// /// The delegate invokation. /// Performs the authentication check. /// /// The corresponding HTTP context. /// An awaitable task. public async Task InvokeAsync(HttpContext httpContext) { if (httpContext.Request.Headers.TryGetValue("Authorization", out var authHeader) && ((string)authHeader).StartsWith("Basic ")) { string encoded = ((string)authHeader).Split(' ', StringSplitOptions.RemoveEmptyEntries).LastOrDefault() ?? ""; string decoded = Encoding.UTF8.GetString(Convert.FromBase64String(encoded)); string[] parts = decoded.Split(':', 2); var principal = validator.ValidateAsync(parts[0], parts[1], httpContext.GetRemoteIpAddress()); if (principal != null) { await next.Invoke(httpContext); return; } } httpContext.Response.Headers["WWW-Authenticate"] = "Basic"; if (!string.IsNullOrWhiteSpace(validator.Realm)) httpContext.Response.Headers["WWW-Authenticate"] += $" realm=\"{validator.Realm}\""; httpContext.Response.StatusCode = StatusCodes.Status401Unauthorized; } } }