我有一个相当奇怪的场景。我在具有MVC4页面和Web API端点的项目上使用autofac。 Autofac正在管理我的模型对象的范围(它反过来管理数据库上下文的范围),我为InstancePerHttpRequest
和InstancePerApiRequest
配置了它,这样每个请求只创建一个数据库上下文。这样我使用的任何数据库对象都附加到同一个请求(上下文是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文档设置AutofacDependencyResolver
是AutofacDependencyResolver
。
对于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在解析InstancePerApiRequest
和InstancePerHttpRequest
时需要使用相同的对象吗?
如果那是不可能的,我可以采取某种方式:
HttpRequestMessage
是API请求,请在PostAuthenticateRequest
期间获取System.Net.Http.DelegatingHandler
并将其用于依赖性解析?我可能还需要认真重新考虑我这样做的方式,因为乍一看似乎不可能按this回答。
编辑:我相信我可以使用HttpRequestMessage
拦截WebAPI请求,从而无需在PostAuthenticateRequest
期间获取{{1}}。但是,这仍然存在确定请求是否是web api请求的问题。
答案 0 :(得分:0)
实现委派处理程序时,可以保证代码在Web API请求中运行。您也可以将其设为全局过滤器。
您可以将MVC部分实现为高优先级授权过滤器,同样,您将保证在此时处于MVC中。