MVC 3,Ninject 2.2。
我有一个场景需要暂时覆盖绑定。覆盖仅适用于Controller中Action的持续时间。
我需要的是这样的事情:
[HttpGet, Authorize(Users="MySpecialAccount")]
public ActionResult Report(string userName) {
var reportViewModel = new ReportViewModel();
using(var block = Kernel.BeginBlock() {
var principal = //load principal info based on userName;
block.Rebind<IMyPrincipal>().ToConstant(principal);
reportViewModel = GetViewModel(); //calls bunch of repos to hydrate view model that reference IMyPrincipal
}
return View(reportViewModel);
}
该应用程序使用Windows身份验证。我有一个自定义提供程序,可以加载自定义主体。我们将这个自定义主体注入我们的repos / services / etc,并帮助我们根据经过身份验证的用户加载适当的数据。这一切都很有效。现在我有一个场景,我在一个动作中使用模拟。原因可能超出范围,但基本上我使用的是HTMLToPDF编写器,它启动一个单独的进程以在不同的帐户下加载HTML / Action。无论如何,因为我冒充这一行动,所有我的回购都无法加载正确的信息,因为它不是提出请求的用户,这是有道理的。所以我发送了一个“who”参数来运行报告,我需要暂时重新绑定自定义主体。
希望这是有道理的。以下是加载自定义主体的当前代码的片段。
In Global.asax:
protected void WindowsAuthentication_OnAuthenticate(Object source, WindowsAuthenticationEventArgs e)
{
if (e.Identity.IsAuthenticated)
{
//goes to db and loads additional info about logged on user. We use this info in repos/services to load correct data for logged on user.
var principal = new PrincipalFactory().GetPrincipal(e.Identity);
e.User = principal;
}
}
//Ninject Binding
Bind<IMyPrincipal>().ToProvider(new MyPrincipalProvider());
//Provider
public class MyPrincipalProvider : Provider<IMyPrincipal>
{
protected override IMyPrincipal CreateInstance(IContext context)
{
var principal = HttpContext.Current.User as IMyPrincipal;
return principal ?? new UnauthenticatedPrincipal(new GenericIdentity("Not Authenticated"));
}
}
感谢您的帮助!
答案 0 :(得分:2)
我想到的一种可能性是使用自定义授权属性:
public class ImpersonateAuthorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var authorized = base.AuthorizeCore(httpContext);
if (!authorized)
{
return false;
}
string username = httpContext.User.Identity.Name;
// or if you wanted to load the username from the request:
// string username = httpContext.Request["username"];
IPrincipal principal = // load principal info based on username;
// Swap the principal for this action
httpContext.User = principal;
return true;
}
}
然后:
[HttpGet]
[ImpersonateAuthorize(Users="MySpecialAccount")]
public ActionResult Report(string userName)
{
// Here this.User will be the custom principal you loaded in
// the authorize attribute
var reportViewModel = new ReportViewModel();
return View(reportViewModel);
}
另一种方法是在DI框架配置级别执行此操作:
public class MyPrincipalProvider : Provider<IPrincipal>
{
protected override IPrincipal CreateInstance(IContext context)
{
var httpContext = HttpContext.Current;
var rd = httpContext.Request.RequestContext.RouteData;
var currentAction = rd.GetRequiredString("action");
var currentController = rd.GetRequiredString("controller");
if (string.Equals("report", currentAction, StringComparison.OrdinalIgnoreCase) &&
string.Equals("users", currentController, StringComparison.OrdinalIgnoreCase))
{
IPrincipal principal = // load principal info based on username;
return principal;
}
var principal = httpContext.User as IPrincipal;
return principal ?? new UnauthenticatedPrincipal(new GenericIdentity("Not Authenticated"));
}
}