I am attempting to configure Basic Authentication on an MVC service in an ASP.NET Core 1.1 application. I would like to indicate a service requires Basic Authentincation by adding an attribute on the service action (rather than allowing basic auth application wide). After doing some reading it seems like the appropriate way to do this is using a Middleware Filter.
The most comprehensive guide I have found on Middleware filters is here
The above post indcates that I need to create a Pipeline class as follows
public class MyPipeline
{
public void Configure(IApplicationBuilder applicationBuilder)
{
var options = // any additional configuration
//I changed this to use the "UseMiddleware"
applicationBuilder.UseMiddleware<AuthenticationMiddleware>(options);
}
}
I also need a middleware class. I have modified and example from here
public class AuthenticationMiddleware
{
private readonly RequestDelegate _next;
public AuthenticationMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
string authHeader = context.Request.Headers["Authorization"];
if (authHeader != null && authHeader.StartsWith("Basic"))
{
//Extract credentials
string encodedUsernamePassword = authHeader.Substring("Basic ".Length).Trim();
Encoding encoding = Encoding.GetEncoding("iso-8859-1");
string usernamePassword = encoding.GetString(Convert.FromBase64String(encodedUsernamePassword));
int seperatorIndex = usernamePassword.IndexOf(':');
var username = usernamePassword.Substring(0, seperatorIndex);
var password = usernamePassword.Substring(seperatorIndex + 1);
//Here is the tricky bit
DBAuth authenticator = new DBAuth(ConnectionString);
if(authenticator.IsAuthorized(username, password))
{
await _next.Invoke(context);
}
else
{
context.Response.StatusCode = 401; //Unauthorized
return;
}
}
else
{
// no authorization header
context.Response.StatusCode = 401; //Unauthorized
return;
}
}
}
}
Question: How do I pass the connection string to the AuthenticationMiddleware class so I can check the username and password against a database? I really want to do it via injection rather than using the Configuration.GetConnectionString() inside the Middleware class.
From the pipeline sample code it seems like options can be passed to the middleware class but I am not sure how to modify the AuthenticationMiddleware class to accept the options or what class options actually is
PS: I know Basic Authentication is bad, but this is the requirement I have been given
You should be able to do it by modifying your Invoke
method from
public async Task Invoke(HttpContext context)
to
public async Task Invoke(HttpContext context, AppDbContext dbContext)
or alternatively
public async Task Invoke(HttpContext context)
{
var dbContext = context.RequestServices.GetService<AppDbContext>();
}
and just normally reigster your AppDbContext
in your application's Startup.cs
public ConfigureServices(IServiceCollection services)
{
services.AddDbContext<AppDbContext>(config =>
{
config.UseXxx(...);
});
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With