2014-12-27 91 views
1

我有一个ApiController和一个控制器在同一个ASP.NET项目。我的想法是,我想将REST API公开给第三方,并在我公开的REST API之上构建一个网站。从MVC消费授权WebAPI 2

我想从我的MVC控制器(在ProfileController中)使用REST API(在ProfileApiController中)。两个控制器都需要进行身份验证,并且ProfileApiController的响应取决于活动的User.Identity。

我该如何做到这一点?下面

代码:

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): 
     } 
    } 

}

我已经尝试过两种方法:

  • 通过电话HttpClient的

    HttpClientHandler h = new HttpClientHandler(); 
        var client = new HttpClient(h); 
        var response = client.GetAsync("http://localhost:4827/api/profile/param/").Result; 
        var m = await response.Content.ReadAsAsync<List<TransferObject>>(); 
        return View(m); 
    
中的WebAPI

但在这里,我坚持从控制器传递身份到ApiController

  • 调用控制器直接

    var pc = DependencyResolver.Current.GetService<ProfileController>(); 
        var r = await pc.GetTenseProfile("param"); 
        var rr = await r.ExecuteAsync(System.Threading.CancellationToken.None); 
        var m = await rr.Content.ReadAsAsync<List<TransferObject>>(); 
        return View(m); 
    

但是这变成一个烂摊子作为pc.Configuration和pc.Request需要配置。这不应该这么难吗?

+0

你可以创建一个业务层,并在两个控制器中调用它 –

+0

看起来像什么? –

+0

这是唯一的方法吗?这对我来说似乎是一种常见的情况? –

回答

2

我会按此顺序走3条路线之一。

  1. 移动您的逻辑是共同的ControllerApiController两者成一个类,然后使用这个类在控制器中。

    [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. 通过AJAX消耗您的API。这是更多的服务器往返行程,但使用您设计的API。使用视图中的参数对API控制器进行AJAX调用。

    [Authorize] 
    public class ProfileController : Controller 
    { 
        public async Task<ActionResult> GetProfile() 
        { 
         return View("myparameter"): 
        } 
    } 
    
  3. 使用基于声明的身份验证,在请求中包含标头。如果你正在保护你的API,那么你可能已经这样做了。使用上面列出的HttpClient,然后根据MVC中的用户在头中添加不记名令牌。

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

    这也可以帮助:http://www.asp.net/web-api/overview/security/individual-accounts-in-web-api

大量的冗余代码中选择2和3这是更好地为你的控制器是不可知的业务逻辑和你的代码是消费。我不认为在每个Action中必须在MVC代码的所有位置创建HttpRequest是一个好习惯。当你不得不重构某些东西的时候,这会导致很多令人头疼的事情发生。

+0

谢谢阿什利!我的意图是稍后开发也使用API​​的移动webapps,这将使用选项三。由于这在所有客户如何接近API方面更一致,您能详细说明最后一个选项吗?目前我有一个ClaimsIdentity,但没有找到我可以通过这个在我的HttpClient –

+0

这个更新有助于选项#3吗? –

+0

太棒了!谢谢 :) –