C# JWT-解密令牌但不验证

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可以在任何时候失效,从而使用户

总结 我创建了一个示例项目来测试ASP.Net核心应用程序中JWT令牌的发布

有关完整示例,请参阅上面的Github回购协议

在JwtService.cs类中,有一个名为GenerateSecurityToken的方法,该方法生成Jwt令牌

AccountController的Login方法调用JwtService类来生成令牌,将令牌保存在cookie中,并为用户id设置另一个cookie

注意:令牌由一个秘密签名,该秘密还附加了一个用户特定的salt。用户salt可以在任何时候失效,从而使用户的令牌无效

令牌也使用加密密钥加密。这使得在JWT.io中检查时标记的主体难以辨认。我相信它被称为JWE

讨论签名和加密顺序

问题 我不希望持有人或任何第三方检查代币的内容。令牌在身份验证中的用途

我的示例代码截取身份验证管道,并使用来自cookie的电子邮件将用户角色从数据库中拉出,并从角色中创建角色声明

你们中的一些人可能已经发现了由于在电子邮件中发布单独的cookie而导致的信息泄漏

理想情况下,我只想在cookie中发出JWE令牌

我想截获身份验证管道,解密令牌,使用电子邮件声明获取用户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哈希非常感兴趣,但我建议您有四种方法:

要生成令牌(序列很重要):

  • 发电站
  • 哈希令牌
  • 然后,当您收到带有请求的承载令牌时(顺序很重要):

  • 德哈什托克
  • 验证特肯
  • 由于这两个过程,JWT生成和哈希非常简单:

    为了获得最佳结果,忘记散列,专注于生成令牌和验证令牌

    在JWT获得成功后,在另一个项目中,将重点放在对任何文本(JWT或其他内容)进行散列和去散列上

    当你两者都成功时,不要互相打电话

    建立新的方法,比如

  • GenerateAndHash(它同时调用GenerateToken和HashToken)
  • VerfyHashAndValidateToken(它同时调用DeHashToken和ValidateToken)
  • 要一步一步地生成和验证JWT,请看以下内容(文章的标题可能会让人困惑,但它以非常简单的方式讨论了.NET Core中的JWT,尤其是我认为在第2部分中)

    散列

    验证散列

    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;
            }