您可以在多个地方执行此操作,但如果您使用的是SessionAuthenticationModule
,则某些过程没有很好地记录,这可能会使使用自定义主体变得棘手。这个答案的其余部分解释了在使用SessionAuthenticationModule
.
覆盖SessionAuthenticationModule.SetPrincipalFromSessionToken
方法。
SessionAuthenticationModule 将安全令牌、主体、身份和声明存储在 cookie 和内存缓存中,以避免在每次请求时都必须往返于身份提供者/令牌服务。没有很好记录的是缓存的存在,它是第一个检查的地方,然后是 cookie,以及对ClaimsPrincipal
.
如果您已经在其中设置了自定义主体ClaimsAuthenticationManager.Authenticate
并且缓存完好无损,那么您的自定义主体很可能已经存在,因为缓存存储了本机 .NET 对象。如果您尚未设置自定义主体,或者未填充缓存,则将从 FedAuth 会话 cookie 中检索安全令牌。
当令牌被序列化/反序列化到 cookie 时,该过程使用自定义序列化,该序列化只能读取和写入IClaimsPrincipal
andIClaimsIdentity
接口(或ClaimsPrinicpal
andClaimsIdentity
类 - 我不记得是哪个)的属性。将不包括任何自定义主体和身份对象属性。可能可以覆盖序列化,但这需要几个(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;
}
}