我目前在使用Windows身份验证的Mvc3应用程序中使用Unity with Unity.Mvc3。我也在阅读关于进行依赖注入的文章,并试图设置一个环境上下文来进行一些授权检查。
我有一个抽象的AuthorizeContext类,它具有静态属性Current,它包含该类的三个实现之一:
-
AuthorizeRoleContext,用于生产,它通过构造函数注入获得一个字符串和一个IPrincipal,并且只是一层间接层,用于在请求或要求授权时调用IPrincipal.IsUserInRole。注入的字符串用作角色的域前缀。
-
AuthorizeContextAllowAll,用于开发,有时用于测试,它总是使用默认构造函数允许所有授权请求和要求。
-
AuthorizeContextAllowNothing,用于测试允许的最低功能,该功能始终拒绝所有授权请求。
-
将来,再添加一个并通过数据库检查授权。。。?
因此,我可以通过以下操作手动连接(例如,在Application_BeginRequest中):
AuthorizeContext.Current=新建AuthorizeRoleContext(HttpContext.Current.User);
然后呼叫
AuthorizeContext.Current.Demand("someRole");
这很好,但我正在寻找正确的方式(和位置)将其与Unity连接起来,同时避免使用服务定位器反模式。所以我的问题是:我该怎么做?
到目前为止,我在Unity注册方面面临的一些挑战:
- 我在Application_Start中没有HttpContext.Current.User,因此当时无法将其注入AuthorizeRoleContext
- 我不知道如何将实现分配给静态AuthorizeContext.Current属性
现在,也许我应该到处做[Authorize(Roles="Role1")],让MVC3做它的事情,但是:
- 我也用它来构建我的菜单,也许还想在其他地方使用它来进行授权检查
- 我想把授权检查换成其他实现(比如allow-all),这样我就不必为每个开发人员/测试人员分配Windows组
- 我似乎必须为具有IPrincipal.IsUserInRole的角色使用域前缀,否则它将无法在dev/test/production中工作。当然,生产是在客户环境中进行的,使用完全不同的域名。这就是我使域名可配置并注入它的原因
- 我想对事物进行单元测试
但也许我仍然走错了路,我正在解决不存在的问题。:)
我不相信这个额外的间接层会增加任何值。IPrincipal已经是一种多态类型,所以你可以用一种更容易的方式来完成你想要的。
您可以只使用Windows身份验证(WindowsPrincipal)提供的IPrincipal,而不是AuthorizeRoleContext。
您可以像这样实现IPrincipal,而不是AuthorizeContextAllowAll:
public AllowAllPrincipal : IPrincipal
{
public bool IsInRole(string role)
{
return true;
}
// also implement the Identity property...
}
代替AuthorizeContextAllowNothing实现如下IPrincipal:
public AllowNothingPrincipal : IPrincipal
{
public bool IsInRole(string role)
{
return false;
}
// also implement the Identity property...
}
要配置它,您可以将其添加到Global.asax.cs:
private void OnAuthenticateRequest(object sender, EventArgs e)
{
this.Context.User = this.container.Resolve<IPrincipal>();
}
要用"真正的"IPrincipal配置Unity,你可以这样设置:
this.container.RegisterType<IPrincipal>(
new InjectionFactory(
_ => HttpContext.Current.User));
使用AllowAllPrincipal配置Unity要容易得多:
this.container.RegisterType<IPrincipal, AllowAllPrincipal>();
同样,AllowNothingPrincipal:
this.container.RegisterType<IPrincipal, AllowNothingPrincipal>();
如果你必须坚持连接你自己的AuthorizeContext,你可以用类似的方式。