由SessionToken设置的自定义主体在应用程序PostAuthenticateRequest中恢复为ClaimsPrincipal

时间:2017-01-30 16:07:22

标签: asp.net-mvc session-cookies windows-authentication claims-based-identity iprincipal

我正在使用Windows身份验证开发Intranet Web App。我使用自定义ClaimsAuthenticationManager使用声明转换。

public class ClaimsTransformer : ClaimsAuthenticationManager
    {
        public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal)
        {
            if (!incomingPrincipal.Identity.IsAuthenticated)
            {
                return base.Authenticate(resourceName, incomingPrincipal);
            }

        var newPrinciPal = CreateApplicationPrincipal(incomingPrincipal.Identity.Name);

        EstablishSession(newPrinciPal);

        return newPrinciPal;
    }

    private void EstablishSession(ClaimsPrincipal newPrinciPal)
    {
        var sessionToken = new SessionSecurityToken(newPrinciPal, TimeSpan.FromHours(8))
        {
            IsPersistent = false,
            IsReferenceMode = true
        };

        FederatedAuthentication.SessionAuthenticationModule.WriteSessionTokenToCookie(sessionToken);
    }

    private ClaimsPrincipal CreateApplicationPrincipal(string userName)
    {
        new SecurityManager().LoginUser(userName);

        var claims = new List<Claim>();

        claims.Add(new Claim(ClaimTypes.Name, userName));

        RPSUser originalIdentity = Thread.CurrentPrincipal.Identity as RPSUser;

        if (originalIdentity != null)
        {
            RPSUserInformation userDetails = originalIdentity.UserDetails;

            int splitIndex = userDetails.FullName.IndexOf(' ');
            claims.Add(new Claim(ClaimTypes.GivenName, userDetails.FullName.Substring(0, splitIndex)));
            claims.Add(new Claim(ClaimTypes.Surname, userDetails.FullName.Substring(splitIndex + 1)));
            claims.Add(new Claim(ClaimTypes.Email, userDetails.Email));
            claims.Add(new Claim(ClaimTypes.WindowsAccountName, userDetails.LanId));
        }

        RPSUser transformedIdentity = new RPSUser(new ClaimsIdentity(claims, "Custom"));
        transformedIdentity.UserDetails = originalIdentity.UserDetails;

        return new RPSPrincipal(transformedIdentity, null);
    }
}

在Global.ascx中我有这段代码

protected void Application_PostAuthenticateRequest()
        {
            try
            {
                var newPrincipal = FederatedAuthentication.FederationConfiguration
                                            .IdentityConfiguration
                                            .ClaimsAuthenticationManager.Authenticate(string.Empty, ClaimsPrincipal.Current);

            SecurityManager.SetIdentityToThread(newPrincipal as RPSPrincipal);
        }
        catch
        {

        }
    }

此外,我可以从Global.asax中的这段代码中检索/反序列化Cookie

void SessionAuthenticationModule_SessionSecurityTokenReceived(object sender,SessionSecurityTokenReceivedEventArgs e)         {             var extendSession = true;

        if (Request.UrlReferrer.AbsolutePath.Equals("/"))
        {
            var principal = e.SessionToken.ClaimsPrincipal as RPSPrincipal;
            SecurityManager.SetIdentityToThread(principal);

            if (extendSession)
            {
                e.SessionToken = new SessionSecurityToken(
                    e.SessionToken.ClaimsPrincipal,
                    TimeSpan.FromHours(8))
                {
                    IsPersistent = false,
                    IsReferenceMode = true
                };

                e.ReissueCookie = extendSession;
            }
        }
    }

但问题是即使我能够在此事件中将cookie反序列化为自定义Principal(RPSPrincipal)并且能够将其设置为线程,随后在Application_PostAuthenticateRequest中(对于相同的请求)我们将丢失自定义主体。我们刚刚收到ClaimsPrincipal。

我在这里做错了什么?如果已经设置了自定义主体且Identity的IsAuthenticated属性已设置为true,我如何确保Windows身份验证不会覆盖主体?

或者无论如何在Application_PostAuthenticateRequest事件中访问sessionSecurityToken?

0 个答案:

没有答案