C# JWT-解密令牌但不验证
总结 我创建了一个示例项目来测试ASP.Net核心应用程序中JWT令牌的发布 有关完整示例,请参阅上面的Github回购协议 在JwtService.cs类中,有一个名为GenerateSecurityToken的方法,该方法生成Jwt令牌 AccountController的Login方法调用JwtService类来生成令牌,将令牌保存在cookie中,并为用户id设置另一个cookie 注意:令牌由一个秘密签名,该秘密还附加了一个用户特定的salt。用户salt可以在任何时候失效,从而使用户的令牌无效 令牌也使用加密密钥加密。这使得在JWT.io中检查时标记的主体难以辨认。我相信它被称为JWE 讨论签名和加密顺序 问题 我不希望持有人或任何第三方检查代币的内容。令牌在身份验证中的用途 我的示例代码截取身份验证管道,并使用来自cookie的电子邮件将用户角色从数据库中拉出,并从角色中创建角色声明 你们中的一些人可能已经发现了由于在电子邮件中发布单独的cookie而导致的信息泄漏 理想情况下,我只想在cookie中发出JWE令牌 我想截获身份验证管道,解密令牌,使用电子邮件声明获取用户salt(来自数据库)并验证令牌 我已经阅读了文档,但无法找到解密令牌的方法 老实说,我甚至不确定令牌发出时的操作顺序(先签名后加密或先加密后签名) 如果有人能给我指出C# JWT-解密令牌但不验证,c#,asp.net-core,jwt,webapi,C#,Asp.net Core,Jwt,Webapi,总结 我创建了一个示例项目来测试ASP.Net核心应用程序中JWT令牌的发布 有关完整示例,请参阅上面的Github回购协议 在JwtService.cs类中,有一个名为GenerateSecurityToken的方法,该方法生成Jwt令牌 AccountController的Login方法调用JwtService类来生成令牌,将令牌保存在cookie中,并为用户id设置另一个cookie 注意:令牌由一个秘密签名,该秘密还附加了一个用户特定的salt。用户salt可以在任何时候失效,从而使用户
JwtSecurityTokenHandler
的源代码,那可能是一个好的开始
短暂性脑缺血发作
public string GenerateSecurityToken(字符串电子邮件、字节[]salt、字符串[]角色)
{
var tokenHandler=new JwtSecurityTokenHandler();
var key=Encoding.ASCII.GetBytes(_secret).Concat(salt).ToArray();
字节[]ecKey=新字节[256/8];
Array.Copy(Encoding.ASCII.GetBytes(_ecKey),ecKey,256/8);
var tokenDescriptor=新的SecurityTokenDescriptor
{
发行人=_发行人,
听众,
主题=新的索赔实体(
新名单
{
新索赔(ClaimTypes.Email,Email)
}),
//.Concat(roles.Select(r=>newclaim(ClaimTypes.Role,r))).ToArray(),
Expires=DateTime.UtcNow.AddMinutes(double.Parse(_expDate)),
SigningCredentials=新的SigningCredentials(新的SymmetricSecurityKey(密钥),SecurityAlgorithms.HmacSha256Signature),
EncryptingCredentials=新的EncryptingCredentials(
新对称安全性(
埃基),
SecurityAlgorithms.Aes256KW,
安全算法.Aes256CbcHmacSha512)
};
var token=tokenHandler.CreateJwtSecurityToken(tokenDescriptor);
返回tokenHandler.WriteToken(令牌);
}
虽然您对JWT哈希非常感兴趣,但我建议您有四种方法:
要生成令牌(序列很重要):
public static bool VerifyHashWith(此字符串存储密码、字符串登录密码)
{
byte[]hashBytes=Convert.FromBase64String(storedPassword);
字节[]salt=新字节[16];
Copy(hashBytes,0,salt,0,16);
var pbkdf2=新的Rfc2898DeriveBytes(登录密码,salt,100000);
byte[]hash=pbkdf2.GetBytes(20);
对于(int i=0;i<20;i++)
{
if(hashBytes[i+16]!=hash[i]){return false;}
}
返回true;
}
您发布的令牌不完整,请编辑并完整发布,同时提供其他相关类代码以识别缺失/错误的部分感谢反馈。我已经编辑了原始问题,添加了一个到示例项目的链接,使其更加简洁。。如果我能解决我的问题,将进行更新。更新2:DecryptToken受保护。我将尝试创建一个新类,该类继承自JwtSecurityTokenHandler
,并公开该方法受保护的字符串解密令牌(JwtSecurityToken jwtToken,TokenValidationParameters validationParameters)```
public string GenerateSecurityToken(string email, byte[] salt, string[] roles)
{
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(_secret).Concat(salt).ToArray();
byte[] ecKey = new byte[256 / 8];
Array.Copy(Encoding.ASCII.GetBytes(_ecKey), ecKey, 256 / 8);
var tokenDescriptor = new SecurityTokenDescriptor
{
Issuer = _issuer,
Audience = _audience,
Subject = new ClaimsIdentity(
new List<Claim>
{
new Claim(ClaimTypes.Email, email)
}),
// .Concat(roles.Select(r => new Claim(ClaimTypes.Role, r))).ToArray()),
Expires = DateTime.UtcNow.AddMinutes(double.Parse(_expDate)),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature),
EncryptingCredentials = new EncryptingCredentials(
new SymmetricSecurityKey(
ecKey),
SecurityAlgorithms.Aes256KW,
SecurityAlgorithms.Aes256CbcHmacSha512)
};
var token = tokenHandler.CreateJwtSecurityToken(tokenDescriptor);
return tokenHandler.WriteToken(token);
}
public static string ToCustomHash(this string text)
{
byte[] salt;
new RNGCryptoServiceProvider().GetBytes(salt = new byte[16]);
var pbkdf2 = new Rfc2898DeriveBytes(text, salt, 100000);
byte[] hash = pbkdf2.GetBytes(20);
byte[] hashBytes = new byte[36];
Array.Copy(salt, 0, hashBytes, 0, 16);
Array.Copy(hash, 0, hashBytes, 16, 20);
var hashedToBase64 = Convert.ToBase64String(hashBytes);
return hashedToBase64;
}
public static bool VerifyHashWith(this string storedPassword, string loginPassword)
{
byte[] hashBytes = Convert.FromBase64String(storedPassword);
byte[] salt = new byte[16];
Array.Copy(hashBytes, 0, salt, 0, 16);
var pbkdf2 = new Rfc2898DeriveBytes(loginPassword, salt, 100000);
byte[] hash = pbkdf2.GetBytes(20);
for (int i = 0; i < 20; i++)
{
if (hashBytes[i + 16] != hash[i]) { return false; }
}
return true;
}