SledgeHammer SledgeHammer - 1 month ago 26
C# Question

Asp.Net Core custom authentication / tying request to user

I have an Asp.Net Core REST service. My boss didn’t want to use JWT to keep things simple, so we’re just putting the username / password in the request:

{
“userName”: “Bob”,
“password”: “password”,
...
}


All my controllers derive from my own ControllerBase class which has a snippet:

public override void OnActionExecuting(ActionExecutingContext context)
{
if (ModelState.IsValid)
{
RequestBase request = (RequestBase)context.ActionArguments.Where(x => x.Value is RequestBase).First().Value;

if (!OnValidateCredentials(request.Username, request.Password))
context.Result = Unauthorized();
else
base.OnActionExecuting(context);
}
...
}


The OnValidateCredentials method just hits up a database and grabs a User object and then validates the password hash. That's all cool.

So question... I'm not really sure how threading works in Core REST, but is it safe to store the User object in ControllerBase as a property so the derived controller can access it? Or is it possible to get multiple calls into the same instance of the controller simultaneously? If so... how can I store the User object so the derived class / method can access it without it getting stomped on by other threads?

Answer

I created an example as a custom middleware for your case (rather than a filter).

Here is how you could use the standard API for Identity, even with your custom requierements. I only coded the part about using the identity. You'll have to provide the custom part.

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    loggerFactory.AddConsole(Configuration.GetSection("Logging"));
    loggerFactory.AddDebug();

    //Custom authentication middleware.
    app.Use(async (context, next) =>
    {
        //Validate security here and proceed to the next line if everything is ok.

        //Replace the parameter with the username from the request.
        context.User = new System.Security.Claims.ClaimsPrincipal(new GenericIdentity("MyUser"));

        //Will return true.
        Console.WriteLine("Is authenticated: ${context.User.Identity.IsAuthenticated}");

        await next();
    });
    app.UseMvc();
}

This code will allow you to use the standard Authorize filter on your controllers. However, I would still try to convince your boss that JWT Tokens are the way to go. They are standard, secure, and better for performance since you don't have to validate the user's data against a database every single call. A custom solution in the security area is usually a solution with easy vulnerabilities to exploit.

Good luck in your implementation.

Comments