【问题标题】:Where is the best place to have custom Principal/Identity set?设置自定义主体/身份的最佳位置在哪里?
【发布时间】:2011-07-26 01:13:14
【问题描述】:

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

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

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

谢谢

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

System.Threading.Thread.CurrentPrincipal = customClaimsPrincipal;

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

【问题讨论】:

  • 为什么不在 Global.asax 的 Application_AuthenticateRequest 事件中执行此操作? (我没有使用过声明身份验证,但使用过表单和编写自定义 IIdentity 等。)
  • 我不想这样做,因为我只想在使用声明身份验证时更改身份。此外,我不是特别喜欢将东西放在 Global.asax 中,因为我需要将代码保留在 HttpModules 中,以便为其他必须做同样事情的网站提供可扩展性。我对此并不陌生,并不完全积极,但我的理解是,我应该确保没有设置(我认为是 SessionAuthentionModule 设置的)其他原则,并且只存在我的自定义原则/身份。

标签: c# .net asp.net authentication claims-based-identity


【解决方案1】:

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

覆盖SessionAuthenticationModule.SetPrincipalFromSessionToken 方法。

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

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

当令牌被序列化/反序列化到 cookie 时,进程使用自定义序列化,该序列化只能读取和写入 IClaimsPrincipalIClaimsIdentity 接口(或 ClaimsPrinicpalClaimsIdentity 的属性)类 - 我不记得是哪个)。将不包括任何自定义主体和身份对象属性。可能可以覆盖序列化,但这需要几个(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;
    }
}

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-20
      • 2011-07-02
      • 2021-12-11
      相关资源
      最近更新 更多