C# 用C中的RS256(非对称)验证JWT#
我有一些这样的代码,我认为它失败了,因为它使用了非对称的RS256,但有“SymmetricSecurityKey()”。这些代币是手工生成的C# 用C中的RS256(非对称)验证JWT#,c#,jwt,rsa,public-key,C#,Jwt,Rsa,Public Key,我有一些这样的代码,我认为它失败了,因为它使用了非对称的RS256,但有“SymmetricSecurityKey()”。这些代币是手工生成的 如何将其转换为使用非对称公钥 另外,我是C#的新手,我想以dotnet标准为目标,所以我也想知道我是否使用了错误的LIB?(取决于预览版) λcat程序.cs 使用制度; 使用System.IdentityModel.Tokens.Jwt; 使用系统文本; 使用System.Linq; 使用Microsoft.IdentityModel.Tokens;
λcat程序.cs
使用制度;
使用System.IdentityModel.Tokens.Jwt;
使用系统文本;
使用System.Linq;
使用Microsoft.IdentityModel.Tokens;
使用System.Security.Cryptography;
命名空间jwttest
{
班级计划
{
静态void Main(字符串[]参数)
{
字符串jwt="2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.6.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2 LKA21H6XXUTXIY8OCARA8ZDNPUNV6AMNP3ECFAWIFYDVJB_cm-GvpCSbr8G8y_Mllj8f4x9nBH8pQux89_6GUYYV7TUPWBFEBLXTF2PZS6YC1ASFLQXENE8DJT9YJPVRZA”;
var pubKey=”2.在中国的一个城市,一个城市,一个城市,一个城市,一个城市,一个城市,一个城市,一个城市,一个城市,一个城市,一个城市,一个城市,一个城市,一个城市,一个城市,一个城市,一个城市,一个城市,一个城市,一个城市,一个城市,一个城市,一个城市,一个城市,一个城市,一个城市,一个城市,一个城市,一个城市,一个城市,一个城市,一个城市,一个城市,一个城市,一个城市,一个城市,一个城市,一个城市,一个城市,一个城市,一个城市,一个城市,一个城市,一个城市,一个城市,一个城市,一个城市,一个城市一个城市,一个城市一个城市,一个城市,一个城市一个城市一个城市,一个城市,一个城市,一个城市一个城市一个城市一个城市XSW4HV43QA+GSYOD2QU68Mb59oSk2OB+BtOLpJofmbGEGgvmwyCI9MwIDAQAB”;
var rawKey=Encoding.ASCII.GetBytes(pubKey);
var tokenHandler=new JwtSecurityTokenHandler();
//var rsa=?
ValidateToken(jwt,新的TokenValidationParameters{
IssuerSigningKey=新对称安全密钥(rawKey)
},
out SecurityToken validatedToken);
}
}
}
C:\src\jwttest(cgt-test-5->origin)
λ点网运行
[2020-08-18T23:41:05.7108585-07:00信息]原始=系统字节[][392]
未处理的异常。Microsoft.IdentityModel.Tokens.SecurityTokenInvalidSignatureException:IDX10503:签名验证失败。尝试的密钥为:“System.Text.StringBuilder”。
捕获的异常:
“System.Text.StringBuilder”。
token:'System.IdentityModel.Tokens.Jwt.JwtSecurityToken'。
位于System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(字符串令牌,令牌验证参数validationParameters)
位于System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken(字符串令牌、令牌验证参数validationParameters、SecurityToken和ValidateToken)
在C:\src\jwttest\Program.cs中的jwttest.Program.Main(字符串[]args)处:第22行
λcat jwttest.csproj
Exe
netcoreapp3.1
λcat jwt.json
{
“alg”:“RS256”,
“典型”:“JWT”
}
{
“sub”:“1234567890”,
“姓名”:“约翰·多伊”,
“管理员”:是的,
“iat”:1516239022
}
- 关于您的第一个问题:
根据您发布的堆栈跟踪,您似乎正在使用.NET Core 3.1。这允许您轻松导入公共X.509/SPKI密钥,如下所示:var pubKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnzyis1ZjfNB0bBgKFMSvvkTtwlvBsaJq7S5wA+kzeVOVpVWwkWdVha4s38XM/pa/yr47av7+z3VTmvDRyAHcaT92whREFpLv9cj5lTeJSibyr/Mrm/YtjCZVWgaOYIhwrXwKLqPr/11inWsAkfIytvHWTxZYEcXLgAXFuUuaS3uF9gEiNQwzGTU1v0FqkqTBr4B8nW3HCN47XUu0t8Y0e+lf4s4OxQawWD79J9/5d3Ry0vbV3Am1FtGJiJvOwRsIfVChDpYStTcHTCMqtvWbV6L11BWkpzGXSW4Hv43qa+GSYOD2QU68Mb59oSk2OB+BtOLpJofmbGEGgvmwyCI9MwIDAQAB"; RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); rsa.ImportSubjectPublicKeyInfo(Convert.FromBase64String(pubKey), out _); // import the public X.509/SPKI DER encoded key
从.NET Core 3.0开始提供 编辑开始: 在早期版本的.NET Core(3.0之前)或.NET Framework中不可用,因此至少需要 对于早期版本,例如.NET Standard 2.0,一种可能是更精确地使用其string jwt = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.POstGetfAytaZS82wHcjoTyoqhMyxXiWdR7Nn7A29DNSl0EiXLdwJ6xC6AfgZWF1bOsS_TuYI3OG85AmiExREkrS6tDfTQ2B3WXlrr-wp5AokiRbz3_oB4OxG-W9KcEEbDRcZc0nH3L7LzYptiy1PtAylQGxHTWZXtGz4ht0bAecBgmpdgXMguEIcoqPJ1n3pIWk_dUZegpqx0Lka21H6XxUTxiy8OcaarA8zdnPUnV6AmNP3ecFawIFYdvJB_cm-GvpCSbr8G8y_Mllj8f4x9nBH8pQux89_6gUY618iYv7tuPWBFfEbLxtF2pZS6YC1aSfLQxeNe8djT9YjpvRZA"; var tokenHandler = new JwtSecurityTokenHandler(); bool verified = false; try { tokenHandler.ValidateToken(jwt, new TokenValidationParameters { ValidateAudience = false, ValidateLifetime = false, ValidateIssuer = false, IssuerSigningKey = new RsaSecurityKey(rsa) }, out _); verified = true; } catch { verified = false; } Console.WriteLine("Verified: " + verified);
类,该类允许以X509/SPKI格式导入公钥(与您无关,也可以使用PKCS#1格式)。在中,您将找到一个示例,说明如何使用Org.BouncyCastle.OpenSsl.PemReader
PemReader
过程,顾名思义,PEM编码,即转换为DER编码(即删除页眉、页脚和换行符,以及按照PemReader
不能执行。还要注意,ImportSubjectPublicKeyInfo()的要求对剩余部分进行Base64解码)
要求在页眉后面至少有一个换行符(PemReader
),在页脚前面至少有一个换行符(----开始公钥------\n
),Base64编码正文中每64个字符后的换行符对于\n----结束公钥------
是可选的 另一种可能性是提供方法的包PemReader
,该方法可以在编码中处理X509/SPKI密钥,类似于opensslkey.DecodeX509PublicKey()
编辑结束ImportSubjectPublicKeyInfo
- 关于第二个问题:
有几个版本,例如.NET Core 3.0实现.NET标准2.1。您使用的包System.IdentityModel.Tokens.Jwt需要.NET标准2.0
是一个支持JSON Web令牌(Jwt)的创建和验证的包。对于已发布的令牌,可以按如下方式实现验证:System.IdentityModel.Tokens.Jwt
var pubKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnzyis1ZjfNB0bBgKFMSvvkTtwlvBsaJq7S5wA+kzeVOVpVWwkWdVha4s38XM/pa/yr47av7+z3VTmvDRyAHcaT92whREFpLv9cj5lTeJSibyr/Mrm/YtjCZVWgaOYIhwrXwKLqPr/11inWsAkfIytvHWTxZYEcXLgAXFuUuaS3uF9gEiNQwzGTU1v0FqkqTBr4B8nW3HCN47XUu0t8Y0e+lf4s4OxQawWD79J9/5d3Ry0vbV3Am1FtGJiJvOwRsIfVChDpYStTcHTCMqtvWbV6L11BWkpzGXSW4Hv43qa+GSYOD2QU68Mb59oSk2OB+BtOLpJofmbGEGgvmwyCI9MwIDAQAB"; RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); rsa.ImportSubjectPublicKeyInfo(Convert.FromBase64String(pubKey), out _); // import the public X.509/SPKI DER encoded key
验证可以通过验证参数进行控制,即通过的第二个参数。由于发布的令牌不包含iss、aud和exp(这可以通过例如on进行验证),因此在我的示例中,它们被排除在验证之外 在本教程中,您将找到更详细的解释,特别是在验证令牌一章中string jwt = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.POstGetfAytaZS82wHcjoTyoqhMyxXiWdR7Nn7A29DNSl0EiXLdwJ6xC6AfgZWF1bOsS_TuYI3OG85AmiExREkrS6tDfTQ2B3WXlrr-wp5AokiRbz3_oB4OxG-W9KcEEbDRcZc0nH3L7LzYptiy1PtAylQGxHTWZXtGz4ht0bAecBgmpdgXMguEIcoqPJ1n3pIWk_dUZegpqx0Lka21H6XxUTxiy8OcaarA8zdnPUnV6AmNP3ecFawIFYdvJB_cm-GvpCSbr8G8y_Mllj8f4x9nBH8pQux89_6gUY618iYv7tuPWBFfEbLxtF2pZS6YC1aSfLQxeNe8djT9YjpvRZA"; var tokenHandler = new JwtSecurityTokenHandler(); bool verified = false; try { tokenHandler.ValidateToken(jwt, new TokenValidationParameters { ValidateAudience = false, ValidateLifetime = false, ValidateIssuer = false, IssuerSigningKey = new RsaSecurityKey(rsa) }, out _); verified = true; } catch { verified = false; } Console.WriteLine("Verified: " + verified);
基本上封装了JWT签名的验证过程。A是一种数据结构,由三部分组成:标题、有效负载和签名,各个部分采用Base64url编码,并用点分隔开来。ValidateToken()
签名是使用各种算法创建的,例如在您的情况下,这意味着数据(Base64url编码的报头和有效负载,包括分隔符)使用算法RSA和PKCS#1 v1.5 padding and digest SHA256进行签名。
令牌的验证对应于签名的验证,其中