如何在 AspNetCore 中仅使用公钥验证使用 x509 签名的 JWT 令牌
Posted
技术标签:
【中文标题】如何在 AspNetCore 中仅使用公钥验证使用 x509 签名的 JWT 令牌【英文标题】:How to verify a JWT token signed with x509 with only a public key in AspNetCore 【发布时间】:2020-01-25 21:53:38 【问题描述】:我有一个 AspNetCore 应用程序,它根据 PFX 证书为我生成 JWT 令牌。
public string GenerateToken()
using (var certificate = new X509Certificate2("certificate.pfx"))
var credentials = new X509SigningCredentials(certificate);
var tokenDescriptor = new SecurityTokenDescriptor
Subject = new ClaimsIdentity(new Claim[]
new Claim(ClaimTypes.Name, "Name"),
new Claim(ClaimTypes.Role, "Tester"),
),
IssuedAt = DateTime.UtcNow,
Expires = DateTime.UtcNow.AddDays(1),
SigningCredentials = credentials
;
var handler = new JwtSecurityTokenHandler();
var token = handler.CreateToken(tokenDescriptor);
return handler.WriteToken(token);
并且使用相同的 PFX,您可以验证签名是否有效。
public ClaimsPrincipal ValidateToken(string token)
using (var certificate = new X509Certificate2("certificate.pfx"))
var key = new X509SecurityKey(certificate);
var validationParameters = new TokenValidationParameters()
ValidateAudience = false,
ValidateIssuer = false,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
IssuerSigningKey = key
;
var handler = new JwtSecurityTokenHandler();
try
var claims = handler.ValidateToken(token, validationParameters, out var validatedToken);
if (claims != null && validatedToken != null)
return claims;
catch (Exception ex)
Debug.WriteLine(ex);
return null;
但这要求只需要验证 JWT 令牌的其他应用程序也可以访问此 PFX 证书。
如果我使用此 PFX 获取生成的令牌
eyJhbGciOiJSUzI1NiIsImtpZCI6IjZEQzE4QTU4MEI4QjIxNzE4MjY5MTdDNkRGRDdGNjM5NEFBMTAwNDgiLCJ4NXQiOiJiY0dLV0F1TElYR0NhUmZHMzlmMk9VcWhBRWciLCJ0eXAiOiJKV1QifQ.eyJ1bmlxdWVfbmFtZSI6Ik5hbWUiLCJyb2xlIjoiVGVzdGVyIiwibmJmIjoxNTY5NDI4MDIwLCJleHAiOjE1Njk1MTQ0MTksImlhdCI6MTU2OTQyODAxOX0.kmszDk3cYEfK7dOzynotOuzTkc0GFIMbRau5ELOUROz5De-6M4YA_tWpjH1Ss6wPM078RKZeMIpolMOGvCLaza1XUp2w7fiJ_zWNJ1r4XiYzfdGiHnrUM7IwjYfwVbV7Ez2sk0FMmka-yO0UeHOKICEoxUAEBA_KzJiWHQfJJssOxcNdu4rwX1CeJ0xnJCKi77GDZ54GhdrQ_NuHzWOQZrsLa7_QfJtNTufOAzAg_kSI7XRCt6LOIkNTiENY_iJSnurlbg0O3VqkmlBvBEOS-ihd0h2Gt_AGEJ22OB4oh7Xip-xf7gm4dPR2u3ISEVmEq5H6J444CDuuKKulB7OLeKEnh9-2fGw8o-q-RIZeOo4r6UqxEW3n6TrEu7hIoAP72x5xc8ptpAPG9GtCsUjMgZcQV4QCLA9zxNxApC6J9cmgZgfI7kTGeardjsy32I23BjUl0AH0c4lh5I3SVeZB7W0mvqLj_UG_O8o57c-0dhU5kcYXJjI5gtQc1gba0ZCokA5NomnHmtpWuNvtRp4O2PwbyjM2O2RxxN07fAkPC1o4Ukm-b_n_OudyznLfmFZwv9wxqn5n-_vIy4WPuM1tm-LIzuXb0dRHDJrI8OPtj43VKNMEkQO604Fb13tVvj3iMB_n3ZWSMuLtMBLNeIED-3eynZfnr0vdMYktHNsvf6o
并把它放在https://jwt.io/ 我只需要公钥来验证签名。
-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxd05ZB9CBfleKjaKzBTv
HylxmrEbm/yPLQKgB3oFwK4qCtcvr9dwsdK7iqFKqrmWIU/6CQrMdrx/k1s0NDWn
jdQCsnTpJ/i/rbGyasL80ilsXjOnA6G07OpvVO88Jn6J9Jz8oDsKSRpk1YV8Z6UM
pGnvlwhkhvTa43sICAPlbdc+FVzT5/3UGHiZ7D0M7I4cMLchrjQM+XP3M7AJl2vC
x/oo7twIzl/J4R5AvKlVz57NSggvyLkAIUIGEM8NpINt1f4aWEthWSLcMf8KUBJX
33MGDWb0HXaA/m1ovxWzmh001qa/miw8xl/ViurEeX9lZZjtNvW3PbV4TB4CxPUj
u61occD/Mek664PBMq+qztM22jg3tyAiIhyntDeLZtRpI3e1TwYMgF21PAc3Vskd
iuqhwFM9V/lVaRJJFJIqd94dOT20FZ78ECFCSnSEjNLaAd2Cm6WzoCf2qYPdb9ZD
2aRUm9+x0bbKxr7dFAM8mC753zuWpAPd0HGo6peAdVBQ4ZYQJ+9Px6lKcSsz4dMq
2OkoBNBCLgDaBZjfbNSxWt57OIDZpteFGgPETYf4JHs85/91JnztS/bAU1h0zrdh
L8s0l8IF89abOt5ZQ6PlwtljhMHBOjO41o/5pFo3hAEmTfv2aUjOH+amhbX9jeOJ
wFtHPr7inytlyltrrNwByeMCAwEAAQ==
-----END PUBLIC KEY-----
我希望其他应用程序仅需要我的公钥,这样我就不必将 PFX 分发到多个应用程序(这允许它们自己生成 JWT 令牌)。
如何仅使用 AspNetCore 中的公钥验证使用 X509 证书签名的 JWT 令牌?
【问题讨论】:
您只能分发证书的公共部分来验证令牌。无需分发 PFX 来验证令牌。 我认为您可以创建仅包含公钥的X509SecurityKey
实例。导出没有私钥的证书,在那里加载,看看会发生什么? :)
@juunas。构造X509SecurityKey
的唯一方法是使用X509Certificate2
。见docs.microsoft.com/en-us/dotnet/api/…。没有别的办法吗?
@Crypt32。你有这方面的例子吗?这真的很有帮助。
在 X509Certificate2 对象上使用 RawData
属性并将字节数组保存到 .CER 文件中。然后在第二个代码中用 sn -p replace.PFX 文件。 CER 文件。
【参考方案1】:
根据@Crypt32 的建议,我能够生成一个单独的证书。
using (var certificate = new X509Certificate2("certificate.pfx"))
using (var file = File.Open(filePath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read))
await file.WriteAsync(certificate.RawData);
有了这个新证书,我能够成功验证令牌,但是在尝试创建新令牌时,我收到了 InvalidOperationException
。
System.InvalidOperationException
HResult=0x80131509
Message=IDX10638: Cannot create the SignatureProvider, 'key.HasPrivateKey' is false, cannot create signatures. Key: [PII is hidden. For more details, see https://aka.ms/IdentityModel/PII.].
Source=Microsoft.IdentityModel.Tokens
StackTrace:
at Microsoft.IdentityModel.Tokens.AsymmetricSignatureProvider..ctor(SecurityKey key, String algorithm, Boolean willCreateSignatures)
at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateSignatureProvider(SecurityKey key, String algorithm, Boolean willCreateSignatures)
at Microsoft.IdentityModel.JsonWebTokens.JwtTokenUtilities.CreateEncodedSignature(String input, SigningCredentials signingCredentials)
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.CreateJwtSecurityTokenPrivate(String issuer, String audience, ClaimsIdentity subject, Nullable`1 notBefore, Nullable`1 expires, Nullable`1 issuedAt, SigningCredentials signingCredentials, EncryptingCredentials encryptingCredentials)
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.CreateToken(SecurityTokenDescriptor tokenDescriptor)
所以这似乎是分发 JWT 令牌验证器的方式。
【讨论】:
与其创建另一个文件(你能确定你有写权限吗?),只需创建一个新的 X509Certificate2 并传入完整证书的 RawData: var publiconlyCert = new X509Certificate2(certificate.RawData ); @9Rune5 -- 该评论应该是它自己的答案。 :) 非常感谢!!以上是关于如何在 AspNetCore 中仅使用公钥验证使用 x509 签名的 JWT 令牌的主要内容,如果未能解决你的问题,请参考以下文章
ASPNetCore MVC ModelValidation-ajax
使用参考令牌的 ASPNETCore SignalR 身份验证