C# ClaimsAuthenticationManager与RoleManager模块并行

C# ClaimsAuthenticationManager与RoleManager模块并行,c#,asp.net,security,wif,claims-based-identity,C#,Asp.net,Security,Wif,Claims Based Identity,出于测试目的,我将经典的会员资格/角色管理器安全设置与新的WIF 4.5 API混合使用。我实现了两个设置了断点的类: public class CustomAuthenticationManager : ClaimsAuthenticationManager { public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal)

出于测试目的,我将经典的会员资格/角色管理器安全设置与新的WIF 4.5 API混合使用。我实现了两个设置了断点的类:

public class CustomAuthenticationManager : ClaimsAuthenticationManager
    {
        public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal)
        {
// Breakpoint here is hit 1st
            if (!incomingPrincipal.Identity.IsAuthenticated)
            {
                return base.Authenticate(resourceName, incomingPrincipal);
            }
            return TransformPrincipal(incomingPrincipal);
        }

        private ClaimsPrincipal TransformPrincipal(ClaimsPrincipal incomingPrincipal)
        {
            // this breakpoint is hit last
            ClaimsIdentity newIdentity = new ClaimsIdentity("Custom");
            newIdentity.AddClaims(incomingPrincipal.Claims);
            // I add some additional claims
            ClaimsPrincipal newPrincipal = new ClaimsPrincipal(newIdentity);
            return newPrincipal;
        }
    }

public class CustomRoleProvider : RoleProvider
{
    public override string[] GetRolesForUser(string username)
    {
        // breakpoint here is hit 2nd
        if(username == "me") return new string [] { "Lead", "Developer" };
        return new string[] {};
    }

    #region Not implemented

    // bunch of not implemented methods

    #endregion
}
现在结果很好,我得到了混合ClaimsPrincipal,它既有名称声明,也有角色声明,还有我在TransformPrincipal方法中添加的声明

但是,调试断点的命中顺序非常奇怪:

1) 首先命中身份验证方法开头的断点

2) 第二次命中GetRolesForUser开头的断点

3) 转换开始时的断点最后命中

这只是VisualStudio的问题,还是在调用GetRolesForUser之前就有可能完成身份验证

RoleManager模块和ClaimsAuthenticationManager如何在管道中工作?是并行还是顺序?两者的混合会成为一个问题吗

编辑:

void Application_PostAuthenticateRequest(object sender, EventArgs e)
        {
            ClaimsPrincipal transformedPrincipal = FederatedAuthentication.FederationConfiguration.IdentityConfiguration.ClaimsAuthenticationManager.Authenticate(null, ClaimsPrincipal.Current);

            Thread.CurrentPrincipal = transformedPrincipal;
            HttpContext.Current.User = transformedPrincipal;
        }
<membership defaultProvider="CustomMembershipProvider">
  <providers>
    <add name="CustomMembershipProvider" type="Tests.CustomMembershipProvider" />
  </providers>
</membership>
<roleManager enabled="true" defaultProvider="CustomRoleProvider">
  <providers>
    <add name="CustomRoleProvider" type="Tests.CustomRoleProvider" />
  </providers>
</roleManager>


<authentication mode="Forms">
      <forms loginUrl="~/Account/Login" timeout="2880" />
    </authentication>

<system.identityModel>
    <identityConfiguration>
      <claimsAuthenticationManager type="Tests.CustomAuthenticationManager, Tests"/>
    </identityConfiguration>
  </system.identityModel>
编辑:

void Application_PostAuthenticateRequest(object sender, EventArgs e)
        {
            ClaimsPrincipal transformedPrincipal = FederatedAuthentication.FederationConfiguration.IdentityConfiguration.ClaimsAuthenticationManager.Authenticate(null, ClaimsPrincipal.Current);

            Thread.CurrentPrincipal = transformedPrincipal;
            HttpContext.Current.User = transformedPrincipal;
        }
<membership defaultProvider="CustomMembershipProvider">
  <providers>
    <add name="CustomMembershipProvider" type="Tests.CustomMembershipProvider" />
  </providers>
</membership>
<roleManager enabled="true" defaultProvider="CustomRoleProvider">
  <providers>
    <add name="CustomRoleProvider" type="Tests.CustomRoleProvider" />
  </providers>
</roleManager>


<authentication mode="Forms">
      <forms loginUrl="~/Account/Login" timeout="2880" />
    </authentication>

<system.identityModel>
    <identityConfiguration>
      <claimsAuthenticationManager type="Tests.CustomAuthenticationManager, Tests"/>
    </identityConfiguration>
  </system.identityModel>

这两个词不应该同时使用。SAM角色管理禁止表单身份验证角色管理,我怀疑您的角色提供程序只是在
web.config
中启用的

我没有在4.5下测试过这个,但我不相信它会改变。在4.0中,仅当用户尚未通过身份验证或当前用户已使用其他身份验证模块建立时,身份验证管理器才会触发。当您同时发出cookie、forms cookie和sam cookie时,后者可能会意外发生。看看我在这方面的博客

虽然我不知道为什么首先命中了身份验证处的断点,但SAM会注意到您的用户是
RolePrincipal
FormsIdentity
,并会尝试从中提取
claimsrincipal
,然后调用身份验证管理器

编辑:在您提供了所有信息之后,关于订单,我仍然有一个小问题。虽然Dominick怀疑角色是延迟加载的,但我无法通过重新编译BCL来确认这一点。相反,
RolePrincipal
似乎急切地在构造函数中添加角色声明(
RolePrincipal
类中的内部
attachrolelems
方法)

不管我怎么看,我认为应该首先调用
GetRolesForUser
,因为这是
ClaimsPrincipal.Current
传递给
Authenticate

如果您的
RoleProvider
预先创建了
RolePrincipal
,将调用
attachrolelems
,并使用
RoleProvider.GetRolesForUser
枚举角色

如果您的
RoleProvider
没有事先创建
RolePrincipal
,则当前的
请求将被删除,这将导致相同的执行路径

Edit2:我找到了可能的罪魁祸首,它是
attachrolleclaims
内部使用的
RoleClaimProvider::Claims
方法。它是通过
yield
惰性地实现的,这意味着除非有人实际枚举角色声明,否则不会创建它们。此“某人”是您在
TransformPrincipal
中的代码:

     ClaimsIdentity newIdentity = new ClaimsIdentity("Custom");
     /* this forces the enumeration */
     newIdentity.AddClaims(incomingPrincipal.Claims);

但是,这也意味着
GetRolesForUser
将在
TransformPrincipal

中最后调用。我使用的不是SessionAuthenticationModule,而是ClaimsAuthenticationManager。当然,这是可能的,但是您的问题缺少有关如何调用它们、索赔经理和角色提供者的详细信息。你在问它们在管道中是如何工作的,但你没有描述哪条管道(你的自定义,内置,哪条,web或非web)。基本上,我让RoleManager模块通过在web.config中定义来使用RoleProvider。当涉及到ClaimsAuthenticationManager时,我正在手动调用Application_PostAuthenticateRequest中的Authenticate方法。您能否显示调用
身份验证的代码?我有我的理论来解释为什么你会看到以这种特定顺序调用的方法,但我想通过验证你的实际操作来补充一些缺失点。我编辑了我的原始帖子,并在应用程序_PostAuthenticateRequest中添加了代码。当你进入ClaimsAuthenticationManager时,你有角色原则吗。IIRC正在进行一些延迟加载,这可以解释为什么在这两者之间的某个地方调用GetRolesForUser。我将完全转储RoleManager,只需在authNmanager中添加角色。Dominick的优点是,传递到Authenticate方法中的主体确实是RolePrincipal。这是否意味着RoleManager模块在管道中更早地构造主体(在ClaimsAuthenticationManager之前),但角色声明在并行过程中稍后添加?或者,它们是否只有在被访问时才被检索(即,当我将RolePrincipal转换为我的主体并遍历现有的角色声明时)?我认为它们是在被访问时被检索的。很乱。我完全删除了角色管理器模块。这就是我计划最终要做的,当我遇到这个问题时,我只是在测试一些东西。谢谢你的帮助:)