在Application处理程序中区分Web API请求和MVC请求

时间:2014-03-05 00:17:23

标签: c# asp.net-mvc-4 asp.net-web-api ioc-container autofac

我有一个相当奇怪的场景。我在具有MVC4页面和Web API端点的项目上使用autofac。 Autofac正在管理我的模型对象的范围(它反过来管理数据库上下文的范围),我为InstancePerHttpRequestInstancePerApiRequest配置了它,这样每个请求只创建一个数据库上下文。这样我使用的任何数据库对象都附加到同一个请求(上下文是EF6上下文)。

这是我的奇怪场景:应用程序支持“代理”功能,其中一个用户可以在页面请求期间成为另一个用户。为了确保偶然AuthorizeAttribute注意这一点,我正在PostAuthenticateRequest事件中捕获请求并执行IPrincipal开关并设置用户我的数据库上下文使用。问题是权限检查:我需要询问我的数据库是否允许用户代理他们想要代理的用户。代码或多或少如下:

protected void Application_PostAuthenticateRequest()
{
    if (!User.Identity.IsAuthenticated)
            return; //nothing to do here if we are not authenticated

    var cookie = Request.Cookies.Get(Controllers.ProxyController.ProxyCookie);

    //The uh-oh occurs at this line...read the rest of the question
    var model = DependencyResolver.Current.GetService<Model.MyModel>();

    //we load the user initially
    //this sets up the user for the rest of the request since our model object should be shared for everything
    var user = model.Users.Where(u => u.username == User.Identity.Name).FirstOrDefault();
    model.User.Current = model.User.Actual = user;

    if (cookie != null)
    {
        //we ask the database if this user can proxy as the cookie'd username
        var proxyAs = model.Users.Where(u => u.username == cookie.Value).FirstOrDefault();
        if (user != null && proxyAs != null)
        {
            if (user.CanProxyAs(proxyAs))
            {
                //this user is allowed to proxy as the specified user
                string[] roles;
                if (proxyAs != null)
                {
                    //get their roles to replace ours
                    roles = proxyAs.groups.SelectMany(g => g.roles).Select(r => r.name).ToArray();
                }
                else
                {
                    //no roles according to the database
                    roles = new string[0];
                }

                //set the model user stuff
                model.User.Actual = user;
                model.User.Current = proxyAs;

                //save the original user IPrincipal
                HttpContext.Current.Items[Controllers.ProxyController.ProxyUser] = User;

                //we need to set the thread current principal as well to keep it in sync:
                // MVC3 stuff (controllers) appears to use HttpContext.Current.User
                // MVC4 stuff (web api) appears to use Thread.CurrentPrincipal
                Thread.CurrentPrincipal = HttpContext.Current.User = new GenericPrincipal(new GenericIdentity(cookie.Value), roles);
            }
        }
    }
}

问题在于我使用DependencyResolver来解析模型对象的部分。

对于MVC请求,这根本不是问题......他们稍后使用DependencyResolver来创建控制器。根据autofac MVC文档设置AutofacDependencyResolverAutofacDependencyResolver

对于Web API请求,但这是一个问题。由于我在此方法中使用AutofacDependencyResolver来解析模型对象,因此已为InstancePerHttpRequest生命周期实例化了模型实例。但是,WebAPI将使用GlobalConfiguration.Configuration.DependencyResolver,根据autofac Web API文档设置为AutofacWebApiDependencyResolver。最终发生的事情是WebAPI调用使用的模型对象没有设置其model.User属性,因为MVC DependencyResolver给了我们不同的模型。

我总是可以设置两个对象,但后来我们遇到了上下文问题。我永远不知道使用哪个解析器:我应该使用MVC DependencyResolver还是Web API依赖解析器?

更复杂的是,web api依赖性解析器只能在HttpRequestMessage的上下文中运行(即在Action方法中)。 PostAuthenticateRequest期间无法使用此对象。

我的问题

我可以告诉autofac在解析InstancePerApiRequestInstancePerHttpRequest时需要使用相同的对象吗?

如果那是不可能的,我可以采取某种方式:

  • 确定请求是API请求还是MVC请求
  • 如果HttpRequestMessage是API请求,请在PostAuthenticateRequest期间获取System.Net.Http.DelegatingHandler并将其用于依赖性解析?

我可能还需要认真重新考虑我这样做的方式,因为乍一看似乎不可能按this回答。

编辑:我相信我可以使用HttpRequestMessage拦截WebAPI请求,从而无需在PostAuthenticateRequest期间获取{{1}}。但是,这仍然存在确定请求是否是web api请求的问题。

1 个答案:

答案 0 :(得分:0)

实现委派处理程序时,可以保证代码在Web API请求中运行。您也可以将其设为全局过滤器。

您可以将MVC部分实现为高优先级授权过滤器,同样,您将保证在此时处于MVC中。

相关问题