我对范围和WIF有一个相当令人困惑的问题。我有一个服务类(SecurityService)来处理所有应用程序安全性。它创建声明,设置ClaimsPrincipal等。它与Ninject绑定。
现在,WIF具有ClaimsAuthorizationManager和ClaimsAuthenticationManager类,以及适当时使用缓存主体的方法。这两个类中的每一个都使用SecurityService,并且创建主体并将其存储在该类中。
我设置了代码,以便在缓存主体时,SecurityService可以接收该缓存版本并将其用作实例变量。该服务绑定InRequestScope()。因为WIF类需要没有参数的构造函数,所以我使用Ninject DependencyResolver.Current.GetService<>()方法。
问题是它似乎要么创建第二个副本,要么在WIF工作发生时RequestScope没有启动。当SecurityService分配给代码中的对象时,SecurityService没有为其分配声明的主体。
以下是身份验证管理器的示例
public class MyClaimsAuthenticationManager : ClaimsAuthenticationManager
{
private readonly SecurityService _MySecurityService;
public HeritageClaimsAuthenticationManager(SecurityService heritageSecurityService)
{
_MySecurityService = heritageSecurityService;
}
public MyClaimsAuthenticationManager()
: this(System.Web.Mvc.DependencyResolver.Current.GetService(typeof(SecurityService)) as SecurityService)
{
}
/// <summary>
/// Provides the framework extension to transform an incoming principal into an application specific principal.
/// </summary>
/// <param name="resourceName"></param>
/// <param name="incomingPrincipal"></param>
/// <returns>An Application specific ClaimsPrincipal</returns>
public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal)
{
if (incomingPrincipal != null && incomingPrincipal.Identity.IsAuthenticated)
{
return TransformPrincipal(incomingPrincipal);
}
//Something is wrong with the incoming principal. Let the base implementation handle it.
return base.Authenticate(resourceName, incomingPrincipal);
}
/// <summary>
/// Given an existing claims principal, transform it to fit the needs of the current application,
/// then store it in session.
/// </summary>
/// <param name="incomingPrincipal"></param>
/// <returns></returns>
public ClaimsPrincipal TransformPrincipal(ClaimsPrincipal incomingPrincipal)
{
_MySecurityService.CreateHeritagePrincipal(incomingPrincipal);
...
return _MySecurityService.Principal;
}
}
由于WIF的构造函数要求,它使用DependencyResolver。此时,_MySecurityService.Principal
具有价值。但是,在请求生命周期的后期,Ninject会返回一个没有Principal的服务。
我还使用IHttpModule拦截WindowsPrincipal并使用身份验证管理器转换每http://leastprivilege.com/2012/04/04/identity-in-net-4-5part-2-claims-transformation-in-asp-net-beta-1/的声明。
这似乎也很合适。当我将InRequestScope()的绑定更改为InSingletonScope()时,一切正常。当然,这不适用于多个用户。另外,当我查看HttpContext.User时,它有我的ClaimsPrincipal。
这是绑定:
Bind<ISecurityService>()
.ToMethod<MySecurityService>(
m => new MySecurityService(
new Collection<ISecurityClaimProvider>()
{
new UserClaimDao(new MyDbContext("MyDbContext"))
}
)).InRequestScope();
DAO正在撤回服务的申请声明,如上所述_MySecurityService.CreateHeritagePrincipal(incomingPrincipal)
总之,一切似乎都正确连线。似乎WIF类中的Ninject操作发生在请求范围之外。
我错过了什么吗?我对范围是否正确?如果是这样,有没有办法围绕它?如果没有,你是如何处理这种情况的?
实际上,我检查过Application_BeginRequest确实在WIF类采取行动之前发生,所以我完全失去了。
答案 0 :(得分:1)
谢天谢地,我弄明白了我的问题,并且按照我的预期让它发挥作用。有两个主要问题。首先,我在发布问题后很快就意识到了。上面的Bind
语句将始终生成一个新实例,因为该方法“new up up”。正确的语法是:
Bind<ISecurityService>().To<SecurityService>()
.InRequestScope()
.WithConstructorArgument("claimProviders",
ctx => new Collection<ISecurityClaimProvider>
{
new UserClaimSecurityDao(
new DbContext("MyDbContext"))
});
这并没有解决我的问题,尽管这是必要的。我使用了Dominick Baier上面引用的文章中提供的HTTPModule。它将逻辑置于“后验证”事件中,我需要将其移至“获取请求状态”事件。我完全正确地观察到服务是在InRequestScope
之外实例化的,然后在该范围内重新实例化。
我做了第三次更改,我没有验证是否有影响。由于NinjectWebCommon动态实例化其HttpModules
,我无法确定我在web.config中设置的两个是否在它们之后加载。我从web.config中删除了它并将它们添加到NinjectWebCommon中,所以现在这是Start()方法:
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
DynamicModuleUtility.RegisterModule(typeof(SessionAuthenticationModule));
DynamicModuleUtility.RegisterModule(typeof(ClaimsTransformationHttpModule));
Boot.Initialize(CreateKernel);
}
我希望我的痛苦可以帮助其他人。
我发现只有在NinjectWebCommon.cs中的Web.Config 和中定义了这些HttpModule时,这才有效。