【问题标题】:JwtSecurityTokenHandler NotSupportedException at EncryptValueEncryptValue 处的 JwtSecurityTokenHandler NotSupportedException
【发布时间】:2018-05-20 18:50:00
【问题描述】:

我有一个 JsonWebTokenFormat 类,它创建一个 JWT 令牌并使用 X.509 RSA SSH 256 证书对其进行签名。

internal class JsonWebTokenFormat : ISecureDataFormat<AuthenticationTicket>
{
    private readonly string _issuer;
    private readonly ICertificateStore _store;

    public JsonWebTokenFormat(string issuer, ICertificateStore store)
    {
        _issuer = issuer;
        _store = store;
    }

    public string Protect(AuthenticationTicket data)
    {
        if (data == null)
        {
            throw new ArgumentNullException("data");
        }

        RSA rsaPrivateKey = _store.GetCurrentUserPrivateCertificate(_issuer);

        SigningCredentials signingCredentials = new SigningCredentials(new RsaSecurityKey(rsaPrivateKey), SecurityAlgorithms.RsaSha256Signature, SecurityAlgorithms.Sha256Digest);

        DateTimeOffset? issued = data.Properties.IssuedUtc;
        DateTimeOffset? expires = data.Properties.ExpiresUtc;

        JwtSecurityToken jwtSecurityToken = new JwtSecurityToken(
            issuer: _issuer,
            claims: data.Identity.Claims,
            notBefore: issued.Value.UtcDateTime,
            expires: expires.Value.UtcDateTime,
            signingCredentials: signingCredentials);
        JwtSecurityTokenHandler jwtSecurityTokenHandler = new JwtSecurityTokenHandler();
        string jwtAuthToken = jwtSecurityTokenHandler.WriteToken(jwtSecurityToken);

        return jwtAuthToken;
    }

    public AuthenticationTicket Unprotect(string jwtToken)
    {
        // read the issuer from the token
        JwtSecurityToken jwtSecurityToken = new JwtSecurityToken(jwtToken);
        RSA rsaPublicKey = _store.GetPublicCertificateForClient(jwtSecurityToken.Issuer);

        TokenValidationParameters tokenValidationParams = new TokenValidationParameters
        {
            ValidIssuer = _issuer,
            RequireExpirationTime = true,
            ValidateIssuer = true,
            RequireSignedTokens = true,
            ValidateLifetime = true,
            ValidateAudience = false,
            IssuerSigningKey = new RsaSecurityKey(rsaPublicKey),
            ValidateIssuerSigningKey = true
        };

        JwtSecurityTokenHandler jwtSecurityTokenHandler = new JwtSecurityTokenHandler();
        SecurityToken tempToken;
        ClaimsPrincipal principal = jwtSecurityTokenHandler.ValidateToken(jwtToken, tokenValidationParams, out tempToken);

        AuthenticationTicket authenticationTicket = new AuthenticationTicket(new ClaimsIdentity(principal.Identity), new AuthenticationProperties());

        return authenticationTicket;
    }
}

ICertificateStore 的实现如下所示:

class MockCertificateStore : ICertificateStore
{
    private readonly X509Certificate2 _certificate;

    public MockCertificateStore()
    {
        _certificate = new X509Certificate2(
                @"C:\certs\test-client.pfx",
                "12345",
                X509KeyStorageFlags.MachineKeySet |
                X509KeyStorageFlags.Exportable);
    }

    public RSA GetCurrentUserPrivateCertificate(string subject)
    {
        return _certificate.GetRSAPrivateKey();
    }

    public RSA GetPublicCertificateForClient(string clientId)
    {
        return _certificate.GetRSAPublicKey();
    }
}

所以我有这个单元测试来测试这个类,它在我的本地机器(和其他开发人员的本地机器)上运行良好,但在我们的 Jenkins 构建环境上失败了。

它失败并出现以下异常:

Test method AuthCore.Tests.Token.JsonWebTokenFormatTests.EnsureProtectGeneratesCorrectAuthToken threw exception: 
System.NotSupportedException: Method is not supported.
Stack Trace:
    at System.Security.Cryptography.RSA.DecryptValue(Byte[] rgb)
    at System.Security.Cryptography.RSAPKCS1SignatureFormatter.CreateSignature(Byte[] rgbHash)
    at System.IdentityModel.Tokens.AsymmetricSignatureProvider.Sign(Byte[] input) in c:\workspace\WilsonForDotNet45Release\src\System.IdentityModel.Tokens.Jwt\AsymmetricSignatureProvider.cs:line 224
    at System.IdentityModel.Tokens.JwtSecurityTokenHandler.CreateSignature(String inputString, SecurityKey key, String algorithm, SignatureProvider signatureProvider) in c:\workspace\WilsonForDotNet45Release\src\System.IdentityModel.Tokens.Jwt\JwtSecurityTokenHandler.cs:line 854
    at System.IdentityModel.Tokens.JwtSecurityTokenHandler.WriteToken(SecurityToken token) in c:\workspace\WilsonForDotNet45Release\src\System.IdentityModel.Tokens.Jwt\JwtSecurityTokenHandler.cs:line 815
    at AuthCore.Token.JsonWebTokenFormat.Protect(AuthenticationTicket data) in C:\Jenkins\workspace\AuthCore\Token\JsonWebTokenFormat.cs:line 38
    at AuthCore.Tests.Token.JsonWebTokenFormatTests.EnsureProtectGeneratesCorrectAuthToken() in C:\Jenkins\workspace\AuthCore.Tests\Token\JsonWebTokenFormatTests.cs:line 34

感谢任何帮助。我查看了一堆 SO 问题,但没有一个有帮助。

【问题讨论】:

  • 但是你没有提到你的构建环境。操作系统、.net 版本等。

标签: c# asp.net authentication jenkins jwt


【解决方案1】:

解决了!

问题在于 RsaSecurityKey 类自 .NET 4.6.0 以来已被弃用。出于某种原因,当在未安装旧版本 .NET 的计算机上使用此类时会抛出异常,但在安装旧版本 .NET 的计算机上却很好。相反,只需使用 X509SecurityKey 类。

有关潜在解决方案,请参阅以下文章: https://q-a-assistant.com/computer-internet-technology/338482_jwt-generation-and-validation-in-net-throws-key-is-not-supported.html

static string GenerateToken()
{
    var tokenHandler = new JwtSecurityTokenHandler();
    var certificate = new X509Certificate2(@"Test.pfx", "123");
    var securityKey = new X509SecurityKey(certificate);

    var tokenDescriptor = new SecurityTokenDescriptor
    {
        Subject = new ClaimsIdentity(),
        Issuer = "Self",
        IssuedAt = DateTime.Now,
        Audience = "Others",
        Expires = DateTime.MaxValue,
        SigningCredentials = new SigningCredentials(
            securityKey,
            SecurityAlgorithms.RsaSha256Signature)
    };

    var token = tokenHandler.CreateToken(tokenDescriptor);
    return tokenHandler.WriteToken(token);
}

static bool ValidateToken(string token)
{
    var tokenHandler = new JwtSecurityTokenHandler();
    var certificate = new X509Certificate2(@"Test.cer");
    var securityKey = new X509SecurityKey(certificate);

    var validationParameters = new TokenValidationParameters
    {
        ValidAudience = "Others",
        ValidIssuer = "Self",
        IssuerSigningKey = securityKey
    };

    var principal = tokenHandler.ValidateToken(token, validationParameters, out SecurityToken securityToken);
    if (principal == null)
        return false;
    if (securityToken == null)
        return false;

    return true;
}

【讨论】:

    猜你喜欢
    • 2014-08-24
    • 2014-10-30
    • 2016-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-01
    • 2014-10-24
    • 2015-12-11
    相关资源
    最近更新 更多