在回收工作进程后从会话cookie中读取不正确的ClaimsIdentity类型

时间:2013-04-15 21:31:29

标签: .net asp.net-mvc asp.net-mvc-4 .net-4.5 claims-based-identity

在VS 2012 / .NET 4.5 / ASP.NET MVC 4应用程序中,我有一个源自ClaimsIdentity的自定义标识类型。它只是向基类添加了一些readonly属性,以便为方便起见从某些声明中读取值:

public class AppIdentity : ClaimsIdentity
{
    public AppIdentity(IEnumerable<Claim> claims) : base(claims, "Custom")

    public string CustomProp { get { return FindFirst("CustomClaim").Value; } }
    // etc.
}

在自定义ClaimsAuthenticationManager中,我将传入的主体转换为包含上述标识的主体,为此主体创建标记并将标记写入cookie:

var claims = new List<Claim>
{
    new Claim("CustomClaim", "CustomValue"),
    // etc.
};
var newPrincipal = new ClaimsPrincipal(new AppIdentity(claims));
var sessionToken = new SessionToken(newPrincipal, TimeSpan,FromHours(24));
FederatedAuthentication.SessionAuthenticationModule
    .WriteSessionTokenToCookie(sessionToken);

如果我在控制器操作中获取后续请求的标识,那么......

var identity = ClaimsPrincipal.Current.Identity;

...我发现有时候identity的运行时类型是AppIdentity,有时它只是它的基类型ClaimsIdentity。我的自定义声明始终显示在Claims的{​​{1}}集合中。

当工作进程被回收时,身份似乎“丢失”了我期望的类型identity。我目前只在此项目中使用IIS Express开发服务器,例如,当我在web.config中进行一些小的更改时,我可以强制执行此操作。之后,标识始终具有AppIdentity类型,而不再是ClaimsIdentity

问题:这种方法是否将Cookie中的自定义声明身份类型保存错误且可能不受支持?会话cookie是否存储了派生AppIdentity的类型信息(我想,这是必要的,以便从cookie中实现正确的身份类型)?

2 个答案:

答案 0 :(得分:3)

在序列化往返过程中,类型标识会丢失。我在这里写到: http://leastprivilege.com/2012/10/08/custom-claims-principals-in-net-4-5/

答案 1 :(得分:0)

您可以实现一个简单的HttpModule来检查主体中的传入标识,并将其转换为您自己的实现

public class MyClaimsAuthenticationModule : IHttpModule
{
    public void Init(HttpApplication context)
    {
        context.PostAuthenticateRequest += Context_PostAuthenticateRequest;

    }

    public void Dispose()
    {
        // Nothing to dispose, method required by IHttpModule
    }

    void Context_PostAuthenticateRequest(object sender, EventArgs e)
    {
        var transformer = FederatedAuthentication.FederationConfiguration.IdentityConfiguration.ClaimsAuthenticationManager;
        if (transformer != null)
        {
            var context = ((HttpApplication)sender).Context;
            var principal = context.User as ClaimsPrincipal;

            var oo = principal.Identity is DaIdentity;
            if (!oo)
                principal = new ClaimsPrincipal(new DaIdentity(principal.Identity as ClaimsIdentity));

            var transformedPrincipal = transformer.Authenticate(context.Request.RawUrl, principal);

            context.User = transformedPrincipal;
            Thread.CurrentPrincipal = transformedPrincipal;
        }
    }
}

然后在Web.config中注册它,就像这样

 <modules runAllManagedModulesForAllRequests="true">

      <add name="TestAuthenticationModule" Type="MyAssemby.MyClaimsAuthenticationModule, MyAssembly" preCondition="managedHandler" />



      <add name="SessionAuthenticationModule" type="System.IdentityModel.Services.SessionAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="managedHandler" />
      <add name="ClaimsAuthorizationModule" type="System.IdentityModel.Services.ClaimsAuthorizationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="managedHandler" />
      <remove name="FormsAuthentication" />
      <remove name="WebDAVModule" />
    </modules>