2013-07-19 49 views
1

我對scope和WIF有一個相當困惑的問題。我有一個處理所有應用程序安全性的服務類(SecurityService)。它創建索賠,設置ClaimsPrincipal等,它與Ninject綁定。Ninject InRequestScope綁定對象在AuthenticationManager執行期間沒有保持狀態定義

現在WIF有ClaimsAuthorizationManager和ClaimsAuthenticationManager班,再加上適當的時候使用緩存的校長,一個辦法。這兩個類中的每一個都使用SecurityService,並且主體被創建並存儲在該類中。

我設置的代碼,以便當主緩存中,SecurityService可以接收緩存版本,並用它作爲一個實例變量。該服務綁定了InRequestScope()。由於WIF類需要一個不帶參數的構造函數,因此我使用Ninject DependencyResolver.Current.GetService <>()方法。

的問題是,它似乎無論是創建的第二個副本,或者當WIF工作中出現的RequestScope還沒有開始。當分配給代碼中的對象時,SecurityService沒有爲其分配聲明的主體。

這是由於WIF的構造要求,認證管理器

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; 
    } 
} 

它使用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

謝天謝地,我想通了,我的問題(一個或多個),和剛剛得到這個,因爲我希望的工作。有兩個主要問題。第一,在發佈我的問題後我很快意識到。上面的Bind語句將始終生成一個新實例,因爲該方法是「新建」類。正確的語法是:

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 中定義了這些HttpModules時,這才起作用。