.NET Core 8.0升级后KeyVaultCryptoProvider.Create方法调用失败求助
.NET 8.0下Azure Key Vault生成JWT令牌的版本兼容问题
我们使用以下代码通过Azure Key Vault密钥生成JWT令牌,该方法原本同时适配.NET Core 6.0和8.0环境:
public string GenerateJwtToken(DateTime expiryDateTime, Microsoft.IdentityModel.Tokens.SecurityKey securityKey) { SigningCredentials signingCredentials = new SigningCredentials(securityKey,SecurityAlgorithms.RsaSha256) { CryptoProviderFactory = new CryptoProviderFactory { CustomCryptoProvider = new Microsoft.IdentityModel.KeyVaultExtensions.KeyVaultCryptoProvider() } }; SecurityTokenDescriptor tokenDescriptor = new SecurityTokenDescriptor { IssuedAt = DateTime.UtcNow, Expires = expiryDateTime, SigningCredentials = signingCredentials }; string token = new JsonWebTokenHandler().CreateToken(tokenDescriptor); return token; }
该代码在.NET Core 6.0中可正常运行,但在.NET 8.0环境下抛出MethodAccessException错误:
System.MethodAccessException: Attempt by method 'Microsoft.IdentityModel.KeyVaultExtensions.KeyVaultCryptoProvider.Create(System.String, System.Object[])' to access method 'Microsoft.IdentityModel.Tokens.CryptoProviderFactory.ShouldCacheSignatureProvider(Microsoft.IdentityModel.Tokens.SignatureProvider)' failed. at Microsoft.IdentityModel.KeyVaultExtensions.KeyVaultCryptoProvider.Create(String algorithm, Object[] args) at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateSignatureProvider(SecurityKey key, String algorithm, Boolean willCreateSignatures, Boolean cacheProvider) at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForSigning(SecurityKey key, String algorithm, Boolean cacheProvider) at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForSigning(SecurityKey key, String algorithm) at Microsoft.IdentityModel.JsonWebTokens.JwtTokenUtilities.CreateSignature(ReadOnlySpan`1 data, Span`1 destination, SigningCredentials signingCredentials, Int32& bytesWritten) at Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler.CreateToken(SecurityTokenDescriptor tokenDescriptor, Boolean setdefaultTimesOnTokenCreation, Int32 tokenLifetimeInMinutes) at Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler.CreateToken(SecurityTokenDescriptor tokenDescriptor)
我们尝试改用JwtSecurityToken和JwtSecurityTokenHandler.WriteToken的方式生成令牌,代码如下:
SigningCredentials signingCredentials = new SigningCredentials(new RsaSecurityKey(new Azure.Security.KeyVault.Keys.Key.ToRSA()), SecurityAlgorithms.RsaSha256); JwtSecurityToken token = new JwtSecurityToken(claims: claims, signingCredentials: signingCredentials); return new JwtSecurityTokenHandler().WriteToken(token);
但仍抛出CryptographicException错误:
System.Security.Cryptography.CryptographicException: Unknown error (0xc100000d) at System.Security.Cryptography.RSABCrypt.TrySignHash(ReadOnlySpan`1 hash, Span`1 destination, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding, Int32& bytesWritten) at System.Security.Cryptography.RSA.SignHash(ReadOnlySpan`1 hash, Span`1 destination, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding) at System.Security.Cryptography.RSABCrypt.SignHash(Byte[] hash, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding) at Microsoft.IdentityModel.Tokens.AsymmetricAdapter.SignRsa(Byte[] bytes) at Microsoft.IdentityModel.Tokens.AsymmetricAdapter.Sign(Byte[] bytes) at Microsoft.IdentityModel.Tokens.AsymmetricSignatureProvider.Sign(Byte[] input) at Microsoft.IdentityModel.JsonWebTokens.JwtTokenUtilities.CreateEncodedSignature(String input, SigningCredentials signingCredentials) at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.WriteToken(SecurityToken token)
所有依赖库已更新至最新版本,请求协助解决该版本兼容问题。
解决方案
1. 替换过时的KeyVault扩展库
Microsoft.IdentityModel.KeyVaultExtensions在.NET 8中已不再兼容,需改用Azure官方的Azure.Security.KeyVault.Keys.Cryptography库处理密钥签名操作。
2. 使用CryptographyClient直接签名JWT内容
正确做法是先构建JWT的头部和载荷,生成待签名字符串,再通过CryptographyClient调用Azure Key Vault的签名接口完成签名,最后组装成完整JWT令牌。示例代码如下:
using Azure.Security.KeyVault.Keys; using Azure.Security.KeyVault.Keys.Cryptography; using System.IdentityModel.Tokens.Jwt; using System.Text; using System.Security.Claims; public async Task<string> GenerateJwtTokenWithKeyVaultAsync(DateTime expiryDateTime, string keyVaultKeyId, TokenCredential credential) { // 构建JWT头部和载荷 var tokenDescriptor = new SecurityTokenDescriptor { IssuedAt = DateTime.UtcNow, Expires = expiryDateTime, Subject = new ClaimsIdentity(new List<Claim>()) // 按需添加自定义声明 }; var tokenHandler = new JwtSecurityTokenHandler(); var jwtToken = tokenHandler.CreateJwtSecurityToken(tokenDescriptor); // 生成待签名的JWT部分(头部.载荷) string unsignedToken = $"{jwtToken.Header.Encode()}.{jwtToken.Payload.Encode()}"; byte[] unsignedTokenBytes = Encoding.UTF8.GetBytes(unsignedToken); // 调用Azure Key Vault完成签名 var cryptoClient = new CryptographyClient(new Uri(keyVaultKeyId), credential); var signResult = await cryptoClient.SignDataAsync(SignatureAlgorithm.RS256, unsignedTokenBytes); // 组装完整JWT令牌 string signature = Base64UrlEncoder.Encode(signResult.Signature); return $"{unsignedToken}.{signature}"; }
3. 依赖包版本确认
确保项目引用以下最新稳定版包:
Azure.Security.KeyVault.KeysAzure.IdentityMicrosoft.IdentityModel.Tokens
错误原因说明
- 第一种错误:
MethodAccessException是因为Microsoft.IdentityModel.KeyVaultExtensions内部调用了.NET 8中已改为内部访问的方法,导致权限不足。 - 第二种错误:
CryptographicException (0xc100000d)是因为Key Vault默认配置下密钥不可导出,本地无法使用导出的RSA密钥完成签名操作。
内容的提问来源于stack exchange,提问作者Renjala RK
相关产品推荐
相关产品推荐

