Ninject InRequestScope绑定对象在AuthenticationManager执行期间不保持状态定义

时间:2013-07-19 17:55:21

标签: asp.net-mvc-4 ninject wif

我对范围和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类采取行动之前发生,所以我完全失去了。

1 个答案:

答案 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时,这才有效。