2014-12-27 58 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

太棒了!謝謝 :) –