4

我一直在使用基于表单和基于声明的身份验证的网站(使用 ASP.NET C#)。我想重写 ClaimsIdentity 类,这样我就可以实现自定义 IsAuthenticated 方法并为特定于声明身份验证的身份添加更多属性。

我目前正在实现一个自定义 WSFederationAuthentionModule,但我试图弄清楚我应该覆盖哪个模块(特别是什么方法),以便我可以设置我的自定义身份/主体而不是默认的 ClaimsPrincipal?

到目前为止,我已经查看了 SessionAuthenticationModule 和 ClaimsPrincipalHTTPModule,但我无法弄清楚主体设置的步骤/覆盖它的最佳方式。

谢谢

补充: 由于我对此有点陌生,所以让我确定这是正确的:设置身份的方法是设置一个自定义主体,该主体设置为使用该身份:

System.Threading.Thread.CurrentPrincipal = customClaimsPrincipal;

或者,如果不需要自定义主体,则可以使用 ClaimsIdentityCollection 构造 ClaimPrincipal 类。

4

2 回答 2

3

您可以在多个地方执行此操作,但如果您使用的是SessionAuthenticationModule,则某些过程没有很好地记录,这可能会使使用自定义主体变得棘手。这个答案的其余部分解释了在使用SessionAuthenticationModule.

覆盖SessionAuthenticationModule.SetPrincipalFromSessionToken方法。

SessionAuthenticationModule 将安全令牌、主体、身份和声明存储在 cookie 和内存缓存中,以避免在每次请求时都必须往返于身份提供者/令牌服务。没有很好记录的是缓存的存在,它是第一个检查的地方,然后是 cookie,以及对ClaimsPrincipal.

如果您已经在其中设置了自定义主体ClaimsAuthenticationManager.Authenticate并且缓存完好无损,那么您的自定义主体很可能已经存在,因为缓存存储了本机 .NET 对象。如果您尚未设置自定义主体,或者未填充缓存,则将从 FedAuth 会话 cookie 中检索安全令牌。

当令牌被序列化/反序列化到 cookie 时,该过程使用自定义序列化,该序列化只能读取和写入IClaimsPrincipalandIClaimsIdentity接口(或ClaimsPrinicpalandClaimsIdentity类 - 我不记得是哪个)的属性。将不包括任何自定义主体和身份对象属性。可能可以覆盖序列化,但这需要几个(3 IIRC)更多的类覆盖层。

您还需要了解基本SetPrincipalFromSessionToken方法创建一个新ClaimsPrincipal对象并将其设置在线程和上下文中的事实,因此即使sessionSecurityToken参数包含自定义主体对象,它也会被转换回ClaimsPrincipal对象。

这是一个示例覆盖方法:

protected override void SetPrincipalFromSessionToken(SessionSecurityToken sessionSecurityToken)
{
    SessionSecurityToken newToken = MyClaimsPrincipalUtility.CreateCustomClaimsPrincipalToken(sessionSecurityToken);

    base.SetPrincipalFromSessionToken(newToken);

    //the following lines need to be set after the base method call, because the base method overwrites the Principal object
    HttpContext.Current.User = newToken.ClaimsPrincipal;
    Thread.CurrentPrincipal = newToken.ClaimsPrincipal;
}

基类 ( SessionAuthenticationModule) 实现如下所示。因此,有几种不同的方法可以实现覆盖和获取自定义声明主体。

protected virtual void SetPrincipalFromSessionToken(SessionSecurityToken sessionSecurityToken)
{
    IClaimsPrincipal fromIdentities = ClaimsPrincipal.CreateFromIdentities(this.ValidateSessionToken(sessionSecurityToken));

    HttpContext.Current.User = (IPrincipal) fromIdentities;
    Thread.CurrentPrincipal = (IPrincipal) fromIdentities;

    //tracing code removed

    this.ContextSessionSecurityToken = sessionSecurityToken;
}

万一你想知道,这里是SessionAuthenticationModule.ContextSessionSecurityToken.

public virtual SessionSecurityToken ContextSessionSecurityToken
{
    get
    {
        return (SessionSecurityToken) HttpContext.Current.Items[(object) typeof (SessionSecurityToken).AssemblyQualifiedName];
    }
    internal set
    {
        HttpContext.Current.Items[(object) typeof (SessionSecurityToken).AssemblyQualifiedName] = (object) value;
    }
}
于 2013-10-17T21:24:43.910 回答
1

您是正确的,因为 HttpModules 是可扩展性的方式,但请确保您实现的任何逻辑都不会抑制应用程序的性能。在向应用程序添加太多 HttpModules 之后,我的网站在性能方面彻底崩溃了。根据您使用的身份验证模型,可能值得缓存查询结果。

您需要弄清楚在什么条件下需要使用您的自定义 ClaimsPrincipal。在你这样做之前,你是在黑暗中刺伤。是否有需要声明身份验证的特定 URL?

于 2012-03-20T12:33:53.100 回答