Wouter Van Ranst
Wouter Van Ranst

Reputation: 529

Consume Authorize WebAPI 2 from MVC

I have an ApiController and a Controller in the same ASP.NET project. The idea is that I want to expose a REST API to 3rd parties and build a website on top of the REST API that I'm exposing.

I want to consume the REST API (in ProfileApiController) from within my MVC controller (in ProfileController). Both controllers require to be authenticated and the response of the ProfileApiController depends on the User.Identity that is active.

How can I achieve this?

Code below:

namespace Controllers
{
    [Authorize]
    public class ProfileApiController : ApiController
    {

        [Route("api/profile/{param}")]
        [HttpGet]
        public async Task<IHttpActionResult> GetProfile(string param)
        {
            return this.Ok<IEnumerable<TransferObject>>( /* business logic */ );
        }
    }


    [Authorize]
    public class ProfileController : Controller
    {
        public async Task<ActionResult> GetProfile()
        {
            //Pseudocode -- this is what I'm looking for
            var api = (reference_to_profileapicontroller);
            api.Authenticate(User.Identity);
            var m = api.GetProfile("myparameter");
            //End Pseudocode

            return View(m):
        }
    }

}

I have already tried two approaches:

but here I'm stuck with passing the identity from the Controller to the ApiController

but this turns into a mess as pc.Configuration and pc.Request need to be configured. This shouldn't be this hard?

Upvotes: 1

Views: 2626

Answers (1)

Ashley Lee
Ashley Lee

Reputation: 3986

I would go one of 3 routes, in this order.

  1. Move your logic that is common to both the Controller and ApiController into a class then use that class in your controller.

    [Authorize]
    public class ProfileApiController : ApiController
    {
        [Route("api/profile/{param}")]
        [HttpGet]
        public async Task<IHttpActionResult> GetProfile(string param)
        {
            // have all business logic in this class
            ProfileClass = newClass = new ProfileClass();
            IList<TransferObject> vm = newClass.GetData();  // from bus rules
    
            return this.Ok<IList<TransferObject>>(vm);
        }
    }
    
    [Authorize]
    public class ProfileController : Controller
    {
        public async Task<ActionResult> GetProfile()
        {
            // have all business logic in this class
            ProfileClass = newClass = new ProfileClass();
            IList<TransferObject> vm = newClass.GetData();  // from bus rules
    
            return View(vm):
        }
    }
    
  2. Consume your API via AJAX. This is more server round trips, but uses your API as it was designed. Use the parameter in the view to make the AJAX call to the API controller.

    [Authorize]
    public class ProfileController : Controller
    {
        public async Task<ActionResult> GetProfile()
        {
            return View("myparameter"):
        }
    }
    
  3. Use Claims based authentication which includes headers in your requests. If you're securing your API, then you're probably already doing this. Use HttpClient as you've listed above, then just add the bearer token in the header based on the user in MVC.

    HttpClient client = new HttpClient();
    client.DefaultRequestHeaders.Authorization = 
        new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
    

    This may also help: http://www.asp.net/web-api/overview/security/individual-accounts-in-web-api

Lots of redundant code in options 2 and 3. It's better for your controllers to be agnostic of the business logic and have your code consume that. I don't think it's a good practice to have to create HttpRequests all over the place in your MVC code in every Action. That's going to lead to alot of headaches down the road when you have to refactor things.

Upvotes: 2

Related Questions