C# 设置自定义主体/标识的最佳位置在哪里?

C# 设置自定义主体/标识的最佳位置在哪里?,c#,.net,asp.net,authentication,claims-based-identity,C#,.net,Asp.net,Authentication,Claims Based Identity,我一直在开发一个网站(使用ASP.NET C#),该网站使用基于表单和基于声明的身份验证。我想重写ClaimSideEntity类,以便实现自定义IsAuthenticated方法,并为声明身份验证的特定身份添加更多属性 我目前正在实现一个自定义的WSFederationAuthentionModule,但我试图找出应该覆盖哪个模块(具体是什么方法),以便设置自定义标识/主体,而不是默认的ClaimsPrincipal 到目前为止,我已经查看了SessionAuthenticationModul

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

我目前正在实现一个自定义的WSFederationAuthentionModule,但我试图找出应该覆盖哪个模块(具体是什么方法),以便设置自定义标识/主体,而不是默认的ClaimsPrincipal

到目前为止,我已经查看了SessionAuthenticationModule和ClaimsPrincipalHTTPModule,但我无法确定主体是在哪一步设置的/覆盖它的最佳方式

谢谢

添加: 因为我在这方面有点生疏,让我确定这是正确的:设置标识的方法是设置一个自定义主体,该主体被设置为使用该标识:

System.Threading.Thread.CurrentPrincipal = customClaimsPrincipal;

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

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


您需要弄清楚在什么情况下需要使用自定义ClaimsPrincipal。在你这么做之前,你是在暗中捅人。是否存在需要声明身份验证的特定URL

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

重写SessionAuthenticationModule.SetPrincipalFromSessionToken方法

SessionAuthenticationModule将安全令牌、主体、标识和声明存储在cookie和内存缓存中,以避免在每次请求时必须往返到标识提供程序/令牌服务。没有很好地记录的是缓存的存在,它是首先检查的位置,然后是cookie,以及序列化
ClaimsPrincipal
的限制

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

当令牌被序列化/反序列化到cookie或从cookie中序列化时,该过程使用自定义序列化,该序列化只能读取和写入
IClaimsPrincipal
IClaimsIdentity
接口(或
claimsprincipal
ClaimsIdentity
类的属性-我记不起是哪个类)。将不包括任何自定义主体和标识对象属性。可以重写序列化,但这需要多个(3 IIRC)层的类重写

您还需要注意一个事实,即base
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;
    }
}

为什么不在Global.asax中的Application_AuthenticateRequest事件中执行此操作?(我没有使用声明身份验证,但使用了表单和书面自定义身份等…)我不想这样做,因为我只想在使用声明身份验证时更改身份。另外,我并不特别喜欢把东西放在Global.asax中,因为我需要将代码保存在HttpModules中,以便为其他需要做同样事情的站点提供可扩展性。我对这一点不太熟悉,也不是完全肯定,但我的理解是,我应该确保设置的其他原则(我认为由SessionAuthentionModule设置)没有设置,只有我的自定义原则/标识存在。