JwtAuthForWebAPI中的SignatureVerificationFailedException

Ada*_*dam 4 access-token jwt asp.net-web-api asp.net-identity json-web-token

我已经连接了JwtAuthForWebAPI nuget项目,但我无法验证生成的令牌.我最终得到500错误.我在生成令牌和使用JwtAuthenticationMessageHandler时都使用完全相同的键值.

这是生成令牌的代码:

var tokenHandler = new JwtSecurityTokenHandler();
var symmetricKey = JsonWebTokenSecretKey.GetBytes();
var now = DateTime.UtcNow;

var tokenDescriptor = new SecurityTokenDescriptor
{
    Subject = new ClaimsIdentity(
        new[]{
            new Claim(JwtClaimKeys.Audience, SessionManager.Current.ApplicationId.ToString()), 
            new Claim(JwtClaimKeys.Subject, userLoginRequest.ApplicationInstanceId.ToString())
        }),
    TokenIssuerName = "My Company",
    Lifetime = new Lifetime(now, now.AddMinutes(tokenLifetimeInMinutes)),
    SigningCredentials = new SigningCredentials(
        new InMemorySymmetricSecurityKey(symmetricKey),
        "http://www.w3.org/2001/04/xmldsig-more#hmac-sha256",
        "http://www.w3.org/2001/04/xmlenc#sha256")
};

tokenDescriptor.Subject.AddClaims(GetRoles(userLoginRequest));

var token = tokenHandler.CreateToken(tokenDescriptor);
return tokenHandler.WriteToken(token);
Run Code Online (Sandbox Code Playgroud)

这是注册身份验证处理程序的代码:

var keyBuilder = new SecurityTokenBuilder();

var jwtHandler = new JwtAuthenticationMessageHandler
{
    Issuer = "My Company",
    AllowedAudience = ApplicationId.ToString(),
    SigningToken = keyBuilder.CreateFromKey(JsonWebTokenSecretKey),
    PrincipalTransformer = new MyUserPrincipleTransformer()
};

config.MessageHandlers.Add(jwtHandler);
Run Code Online (Sandbox Code Playgroud)

这是我得到的错误:

{"Message":"An error has occurred.","ExceptionMessage":"IDX10503: Signature validation failed. Keys tried: 'System.IdentityModel.Tokens.InMemorySymmetricSecurityKey\r\n'.\nExceptions caught:\n ''.\ntoken: '{\"typ\":\"JWT\",\"alg\":\"HS256\"}.{\"aud\":\"1\",\"sub\":\"3\",\"role\":[\"User\",\"Admin\"],\"iss\":\"My Company\",\"exp\":1429547369,\"nbf\":1429543769}'","ExceptionType":"System.IdentityModel.SignatureVerificationFailedException",
"StackTrace":"   
at System.IdentityModel.Tokens.JwtSecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters)\r\n   
at System.IdentityModel.Tokens.JwtSecurityTokenHandler.ValidateToken(String securityToken, TokenValidationParameters validationParameters, SecurityToken& validatedToken)\r\n   
at JwtAuthForWebAPI.JwtSecurityTokenHandlerAdapter.ValidateToken(IJwtSecurityToken securityToken, TokenValidationParameters validationParameters)\r\n   
at JwtAuthForWebAPI.JwtAuthenticationMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n   
at System.Web.Http.HttpServer.<SendAsync>d__0.MoveNext()"}
Run Code Online (Sandbox Code Playgroud)

这是一个示例JSON令牌:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiIxIiwic3ViIjoiMyIsInJvbGUiOlsiVXNlciIsIkFkbWluIl0sImlzcyI6Ik15IENvbXBhbnkiLCJleHAiOjE0Mjk1NTE4MjgsIm5iZiI6MTQyOTU0ODIyOH0.9wA_RBir9u7Cn_-Fy2T-Q_IDUfz6B928IEbIgXD9Bug
Run Code Online (Sandbox Code Playgroud)

有趣的是,我可以使用我的密钥使用http://jwt.io验证令牌.我怀疑它可能与JwtAuthForWebAPI库有什么关系,看看与System.Identity JWT库生成的不同的东西?

小智 6

这是Jamie(JwtAuthForWebAPI包的作者).服务器配置代码 - 具体而言SecurityTokenBuilder.CreateFromKey(string)- 假定给定的字符串是base64编码的.要么是,要么需要假设或参数来指示用于转换为字节数组的编码.我选择假设字符串是base64编码的.我确信有一种更清晰的方法可以将字符串密钥转换为SecurityToken,但这就是今天代码的方式.

JwtAuthForWebAPI.SampleClient项目中的SmokeTests.cs中,您可以看到我使用了该Convert.FromBase64String()方法,而不是使用类中的GetBytes()方法Encoding:

public const string SymmetricKey = "YQBiAGMAZABlAGYAZwBoAGkAagBrAGwAbQBuAG8AcABxAHIAcwB0AHUAdgB3AHgAeQB6ADAAMQAyADMANAA1AA==";

// ...

var key = Convert.FromBase64String(SymmetricKey);
var credentials = new SigningCredentials(
    new InMemorySymmetricSecurityKey(key),
    "http://www.w3.org/2001/04/xmldsig-more#hmac-sha256",
    "http://www.w3.org/2001/04/xmlenc#sha256");
Run Code Online (Sandbox Code Playgroud)

随意使用您当前的令牌生成代码,但在服务器上...

尝试在服务器配置代码中指定base64编码的JsonWebTokenSecretKey版本.您可以使用https://www.base64encode.org/这样的网站对其进行编码,或尝试使用以下代码:

var base64key = Convert.ToBase64String(Encoding.UTF8.GetBytes(JsonWebTokenSecretKey));

var keyBuilder = new SecurityTokenBuilder();
var jwtHandler = new JwtAuthenticationMessageHandler
{
    Issuer = "My Company",
    AllowedAudience = ApplicationId.ToString(),
    SigningToken = keyBuilder.CreateFromKey(base64key),
    PrincipalTransformer = new MyUserPrincipleTransformer()
};
Run Code Online (Sandbox Code Playgroud)

让我知道这是否有效.

此外,我将更新库以捕获SignatureVerificationFailedException异常并返回401,而不是让内部服务器发生错误.您仍然需要将密钥指定为base64字符串,但至少此类配置问题不会导致500错误.

请再次告诉我,如果这样做的话.