0

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?

2
  • Why not use Basic authentication if you really want to send a username/password couple? Although you CAN store a value in a property of a controller since a new instance is created at each request, I would recommend you populate the Request object. It is way more standard. Commented Oct 31, 2016 at 23:47
  • @gretro... you mean some property in this.Request? Can you provide a small example of how to do it "the right way"? Commented Oct 31, 2016 at 23:52

1 Answer 1

4

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.

Sign up to request clarification or add additional context in comments.

3 Comments

Sweet! Thanks. Yeah, I tried with JWT and already had it working. He said they tried something similar before with expiring tokens, etc. and customers said it was a PITA. If it fails validation, I just "return;" or throw an exception or something?
No, you continue with the next middleware. Make sure you secure the API with the Authorize filter and the right response will be sent back (401 if unauthorized or whatever response your service would return otherwise). Also, by doing it this way, you leave yourself open to implement a better solution for authentication later on. You can even load roles and so on with this solution (use a GenericPrincipal if you want to load roles).
GenericIdentity ~~ Save my day.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.