For some of my pet projects, I would like to activate the basic authentication for protecting my web API services from unwanted accesses. .Net core allows us to register our middleware to be used as a pipeline in application scope so that we can inject our custom code for handling request before they go to our service. In the code listing below, I show you how to create a middleware and use it
1. Create basic authentication middleware
public class BasicAuthMiddleware { private readonly RequestDelegate _next; private readonly string _realm; public BasicAuthMiddleware(RequestDelegate next, string realm) { _next = next; _realm = realm; } public async Task Invoke(HttpContext context) { string authHeader = context.Request.Headers["Authorization"]; if (authHeader != null && authHeader.StartsWith("Basic ")) { // Get the encoded username and password var encodedUsernamePassword = authHeader.Split(' ', 2, StringSplitOptions.RemoveEmptyEntries)[1]?.Trim(); // Decode from Base64 to string var decodedUsernamePassword = Encoding.UTF8.GetString(Convert.FromBase64String(encodedUsernamePassword)); // Split username and password var username = decodedUsernamePassword.Split(':', 2)[0]; var password = decodedUsernamePassword.Split(':', 2)[1]; // Check if login is correct if (IsAuthorized(username, password)) { await _next.Invoke(context); return; } } // Return authentication type (causes browser to show login dialog) context.Response.Headers["WWW-Authenticate"] = "Basic"; // Add realm if it is not null if (!string.IsNullOrWhiteSpace(_realm)) { context.Response.Headers["WWW-Authenticate"] += $" realm=\"{_realm}\""; } // Return unauthorized context.Response.StatusCode = (int)HttpStatusCode.Unauthorized; } // Make your own implementation of this public bool IsAuthorized(string username, string password) { IConfiguration config = new ConfigurationBuilder() .AddJsonFile("appsettings.json", true, true) .Build(); var basicAuthUserName = config["BasicAuth:UserName"]; var basicAuthPassword = config["BasicAuth:Password"]; // Check that username and password are correct return username.Equals(basicAuthUserName, StringComparison.InvariantCultureIgnoreCase) && password.Equals(basicAuthPassword); } }
The code does nothing else than reading out the HTTP request header and checks if Authorization is set. If there is any, then check if it is a Basic authentication. If it has the schema of Basic authentication, then decode the username and password with Base64 and check with the user name and password which saved in appsettings.json file.
The appsettings.json has following structure
{ "ConnectionString": "Server=server_ip;Database=database_name;Uid=db_user_name;Pwd=db_user_password;SslMode=none", "BasicAuth": { "UserName": "user_name", "Password": "password" }, "Logging": { "IncludeScopes": false, "Debug": { "LogLevel": { "Default": "Warning" } }, "Console": { "LogLevel": { "Default": "Warning" } } } }
2. Use Basic authentication middleware
Just extend the Configure function with following codes
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseMiddleware<BasicAuthMiddleware>("tetxua.com"); app.UseMvc(); }
3. Postman
In Postman, you have to provide the basic authentication for access the REST api