using System; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Microsoft.AspNetCore.Http { /// /// Implements a basic authentication. /// public class BasicAuthMiddleware { private readonly RequestDelegate next; private readonly string realm; private readonly Func userPasswordAuth; /// /// Initializes a new instance of the class. /// /// The following delegate in the process chain. /// The realm to display when requesting for credentials. /// The function (user, passwd) => result to validate username and password. public BasicAuthMiddleware(RequestDelegate next, string realm, Func userPasswordAuth) { this.next = next; this.realm = realm; this.userPasswordAuth = userPasswordAuth; } /// /// 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(':'); if (parts.Length >= 2) { string username = parts[0].Trim().ToLower(); string password = parts[1].Trim(); if (userPasswordAuth(username, password)) { await next.Invoke(httpContext); return; } } } httpContext.Response.Headers["WWW-Authenticate"] = "Basic"; if (!string.IsNullOrWhiteSpace(realm)) { httpContext.Response.Headers["WWW-Authenticate"] += $" realm=\"{realm}\""; } httpContext.Response.StatusCode = StatusCodes.Status401Unauthorized; } } }