【问题标题】:Consume Authorize WebAPI 2 from MVC从 MVC 使用 Authorize WebAPI 2
【发布时间】:2014-12-29 22:51:45
【问题描述】:

我在同一个 ASP.NET 项目中有一个 ApiController 和一个 Controller。我的想法是我想向第三方公开一个 REST API,并在我公开的 REST API 之上构建一个网站。

我想从我的 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调用WebApi

        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);
    

但在这里我坚持将身份从 Controller 传递到 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。这应该没那么难吧?

【问题讨论】:

  • 您可以创建一个业务层并在两个控制器中调用它
  • 那会是什么样子?
  • 这是唯一的方法吗?这对我来说似乎很常见?

标签: asp.net-mvc razor asp.net-web-api2 authorize


【解决方案1】:

我会按照这个顺序走 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 不是一个好习惯。当您必须重构事物时,这将导致很多令人头疼的问题。

【讨论】:

  • 谢谢阿什利!我的意图是稍后开发也使用 API 的移动 web 应用程序,这将使用选项三。由于这在所有客户端处理 API 的方式上更加一致,您能否详细说明最后一个选项?目前我有一个 ClaimsIdentity 但还没有找到如何在我的 HttpClient 中传递它
猜你喜欢
  • 2022-01-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-25
  • 1970-01-01
  • 2011-06-07
  • 2013-11-25
  • 1970-01-01
相关资源
最近更新 更多