使用 JwtSecurityTokenHandler 反序列化后 ClaimsIdentity AuthenticationType 发生更改

Bar*_*osz 4 c# authentication claims-based-identity asp.net-web-api

首先,更广阔的背景。

我正在开发一个由单独的 Web API 支持的 Web 应用程序。Web 应用程序中的身份验证应基于 ActiveDirectory,并且应由 Web API 处理。

因此, Web 应用程序上LogIn的操作AccountController仅向AuthenticationController- 发送一个发布请求,并且我使用 UserPrincipal 和 PrimaryContext 进行 AD 身份验证。身份验证工作正常,我创建了一些声明。

当我需要将结果发回网络应用程序时,问题就开始了,以便我可以像下面这样进行“登录”

if (result.Claims == null)
{
    this.Logger.Error($"Something went wrong when discovering identity of user [{model.UserName}]");
    throw new InvalidOperationException(Strings_Error.ErrorWhileDiscoveringUserIdentity);
}

IAuthenticationManager authenticationManager = this.HttpContext.GetOwinContext().Authentication;
authenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
authenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = false }, result.Claims);
Run Code Online (Sandbox Code Playgroud)

我正在使用 JwtSecurityTokenHandler 序列化声明,以便我可以将它们附加到来自 Web Api 控制器的响应消息。序列化发生如下:

public static string GenerateToken(this ClaimsIdentity identity)
{
    SymmetricSecurityKey securityKey = new SymmetricSecurityKey(Encoding.Default.GetBytes(ClaimsIndentitySerializer.SecurityKey));
    SigningCredentials signingCredentials = new SigningCredentials(securityKey,SecurityAlgorithms.HmacSha256Signature);
    JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();

    SecurityTokenDescriptor tokenDescriptor = new SecurityTokenDescriptor
    {
        Subject = identity,
        SigningCredentials = signingCredentials,
        Issuer = IssuerKey,
        Audience = "http://www.mycompany.com",
    };

    SecurityToken token = tokenHandler.CreateToken(tokenDescriptor);
    string tokenString = tokenHandler.WriteToken(token);

    return tokenString;
}
Run Code Online (Sandbox Code Playgroud)

然后从字符串生成声明:

public static ClaimsIdentity ReadToken(this string token)
{
    JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();
    SymmetricSecurityKey securityKey = new SymmetricSecurityKey(Encoding.Default.GetBytes(ClaimsIndentitySerializer.SecurityKey));

    TokenValidationParameters validationParameters = new TokenValidationParameters()
    {
        ValidAudience = "http://www.mycompany.com",
        ValidIssuer = IssuerKey,
        IssuerSigningKey = securityKey
    };

    SecurityToken validatedToken = new JwtSecurityToken() as SecurityToken;
    ClaimsPrincipal claimsPrincipal = tokenHandler.ValidateToken(token, validationParameters, out validatedToken);

    return claimsPrincipal.Identity as ClaimsIdentity;
}
Run Code Online (Sandbox Code Playgroud)

我创建了一个单元测试来检查处理后的声明是否匹配。而且,令我惊讶的是,它们有显着的不同。

public void TestClaimsSerialization()
{
    ClaimsIdentity identity = new ClaimsIdentity(DefaultAuthenticationTypes.ApplicationCookie, ClaimsIdentity.DefaultNameClaimType, ClaimsIdentity.DefaultRoleClaimType);
    identity.AddClaim(new Claim("http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider", "Active Directory"));
    identity.AddClaim(new Claim(ClaimTypes.Name, "TestName"));
    identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, "TestNameIdentifier"));
    var token = identity.GenerateToken();
    var deserialized = token.ReadToken();
    Assert.Equal(identity.Name, deserialized.Name);
    Assert.Equal(identity.Claims.FirstOrDefault(x=>x.Type == ClaimTypes.NameIdentifier).Value, deserialized.Claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier).Value);
    Assert.Equal(identity.AuthenticationType, deserialized.AuthenticationType); //the last assert fails
}
Run Code Online (Sandbox Code Playgroud)

错误是 Expected: ApplicationCookie Actual: AuthenticationTypes.Federation

其他断言都可以,所以这些值实际上被保留了。

知道为什么吗?

小智 5

AuthenticationType我通过添加参数解决了同样的问题TokenValidationParameters

var validationParameters = new TokenValidationParameters
{
    RequireExpirationTime = true,
    RequireSignedTokens = true,
    ValidateIssuer = true,
    ValidIssuer = issuer,
    ValidateIssuerSigningKey = true,
    IssuerSigningKey = signingKey,
    ValidateAudience = true,
    ValidAudience = audience,
    ValidateLifetime = true,
    AuthenticationType = "ApplicationCookie"
};
Run Code Online (Sandbox Code Playgroud)