1

我在范围和 WIF 方​​面遇到了一个相当令人困惑的问题。我有一个处理所有应用程序安全性的服务类 (SecurityService)。它创建声明,设置 ClaimsPrincipal 等。它与 Ninject 绑定。

现在 WIF 具有 ClaimsAuthorizationManager 和 ClaimsAuthenticationManager 类,以及在适当时使用缓存主体的方法。这两个类中的每一个都使用 SecurityService,并且主体是在该类上创建和存储的。

我设置了代码,以便在缓存主体时,SecurityService 可以接收该缓存版本并将其用作实例变量。服务绑定 InRequestScope()。因为 WIF 类需要不带参数的构造函数,所以我使用 Ninject DependencyResolver.Current.GetService<>() 方法。

问题是它似乎正在创建第二个副本,或者在 WIF 工作发生时 RequestScope 尚未启动。将 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 操作似乎发生在请求范围之外。

我错过了什么吗?我对范围正确吗?如果是这样,有没有办法绕过它?如果没有,您如何处理这种情况?

实际上,我在 WIF 类采取行动之前检查了 Application_BeginRequest 确实发生了,所以我完全不知所措。

4

1 回答 1

1

谢天谢地,我发现了我的问题,并让它按我的预期工作。有两个主要问题。首先,我在发布我的问题后很快意识到。上面的Bind语句将始终生成一个新实例,因为方法“新建”了类。正确的语法是:

Bind<ISecurityService>().To<SecurityService>()
    .InRequestScope()
    .WithConstructorArgument("claimProviders",
        ctx => new Collection<ISecurityClaimProvider>
            {
                new UserClaimSecurityDao(
                new DbContext("MyDbContext"))
            });

尽管这是必要的,但这并没有解决我的问题。我使用了 Dominick Baier 在上面引用的文章中提供的 HTTPModule。它将逻辑放在“身份验证后”事件中,我需要将其移至“获取请求状态”事件。我完全正确地观察到该服务正在外部实例化InRequestScope,然后在该范围内重新实例化一次。

我进行了第三次更改,但我没有验证是否有影响。由于 NinjectWebCommonHttpModules动态实例化它,我不能确定我在 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);
}

我希望我的痛苦可以帮助其他人。

我发现只有在 Web.ConfigNinjectWebCommon.cs 中都定义了这些 HttpModules 时,这才有效。

于 2013-07-22T16:22:29.320 回答