如何在C#中从RSA私钥和发行者生成授权令牌?

时间:2020-06-15 21:00:40

标签: c# jwt rsa

我需要使用JWT授权令牌登录到Zello API。 Zello提供了一个私有和公共的RSA256密钥,以及一个颁发者。他们生成了一个有效期为30天的开发令牌,我已成功使用该令牌连接到其API。现在,我需要生成自己的JWT令牌。他们的文档(https://github.com/zelloptt/zello-channel-api/tree/master/auth)解释说,我必须使用颁发者和有效期提出索赔-没问题。然后,我将使用RSA256私钥字符串以及声明来生成我的JWT令牌。他们在Go,PHP和JS中的示例看起来非常简单。例如这是他们的JS示例:https://github.com/zelloptt/zello-channel-api/blob/master/auth/js/tokenmanager.js 我花了几天的时间在stackoverflow中搜索如何在C#中执行此操作。在这方面有很多很好的答案,但是对于RSA和没有pem文件的解决方案而言却不是。 我已经安装了许多NuGet软件包来尝试为我提供帮助,包括:Portable.BouncyCastle,jose-jwt,Newtonsoft.Json和Microsoft.IdentityModel.JsonWebTokens。 我的障碍是如何从我的声明和私钥字符串(不在pem文件中)生成安全性/授权JWT令牌。 请注意,由于这是RSA,因此我需要一个非对称安全密钥,而不是对称密钥。我对此是全新的,我认为我可能会缺少一些基本知识。

这是我的代码,我认为这最终是我的答案(我想我是从另一个stackoverflow答案中获得此部分内容的。)但是,它引发了异常“无法读取RSA私钥”。我认为这可能是因为它期望同时存在公共密钥和私有密钥-我可以这样做-但我不知道如何格式化?我还想知道我是否可能被迫使用Zello给我的公钥和私钥创建PEM文件,因此我可以将其读入并仅获取用于生成令牌的私钥。虽然我不确定如何创建和格式化PEM文件? 私钥和公钥只是Zello给我的字符串,看起来像: ----- BEGIN私钥----- MIIBvQIBADANBgkqhkiG9w0BAQE ...-----结束私钥----- -----开始公钥-----..------结束公钥-----

我认为我的主要障碍是尝试了解并使用满足我需要的库之一。似乎简单的事情变得过于复杂。 任何建议将不胜感激。

public static string CreateJWTSecurityToken(Company company)
{

    DateTime parsedDate = DateTime.UtcNow.AddMinutes(5);
    var claims = new List<System.Security.Claims.Claim>
    {
        new System.Security.Claims.Claim("iss", company.ZelloIssuer),
        new System.Security.Claims.Claim("exp", TimeUtils.ToUnixTime(parsedDate).ToString()),
    };

    RSAParameters rsaParams;
    using (var tr = new StringReader(company.ZelloPrivateKey))
    {
        var pemReader = new PemReader(tr);
        var keyPair = pemReader.ReadObject() as AsymmetricCipherKeyPair;
        if (keyPair == null)
        {
            throw new Exception("Could not read RSA private key");
        }
        var privateRsaParams = keyPair.Private as RsaPrivateCrtKeyParameters;
        rsaParams = DotNetUtilities.ToRSAParameters(privateRsaParams);
    }
    using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
    {
        rsa.ImportParameters(rsaParams);
        Dictionary<string, object> payload = claims.ToDictionary(k => k.Type, v => (object)v.Value);
        return Jose.JWT.Encode(payload, rsa, Jose.JwsAlgorithm.RS256);
    }
}

更新: 我在这里找到了部分答案:https://mac-blog.org.ua/dotnet-core-firebase-jwt/

这是帮助我将私钥仅用作字符串的代码段:

using (StringReader sr = new StringReader(company.ZelloPrivateKey))
{
    PemReader pr = new PemReader(sr);
    key = (RsaPrivateCrtKeyParameters)pr.ReadObject(); //no more keyPair because I just have the privKey only
}

我的下一个问题是,当被PemReader读取时,私钥返回NULL。 很明显,它不喜欢我的私钥的格式或内容。 我尝试过同时包含和排除页眉和页脚,还尝试删除cr / lfs以及将它们留在里面。还没有运气,但是我必须亲近。我的私钥长度(不带页眉或页脚)为1674。

更新:通过分析以Zello为例提供的Go代码文件,我发现他们使用的是PKCS#8,它与OpenSSL的“旧版PEM”加密不同(但类似)。因此,这可以解释为什么PemReader无法读取我的私钥。 现在,我正在研究如何以其他方式阅读它。我正在查看以下链接:How read a PKCS8 encrypted Private key which is also encoded in DER with bouncycastle?

更新:

下面是我用来生成JWT身份验证令牌的最终方法。但是,当我尝试登录时,Zello不会接受该令牌,因此我仍然有一些不对的地方。有人知道我在做什么错吗?

public static string CreateToken(Company company)
        {
            DateTime parsedDate = DateTime.UtcNow.AddMinutes(5);
            var claims = new List<System.Security.Claims.Claim>
            {
                new System.Security.Claims.Claim("iss", company.ZelloIssuer),
                new System.Security.Claims.Claim("exp", TimeUtils.ToUnixTime(parsedDate).ToString()),
            };

            var jwt = string.Empty;
            var source = System.Convert.FromBase64String(company.ZelloPrivateKey);

            using (RSA rsa = RSA.Create())
            {
                rsa.ImportPkcs8PrivateKey(source, out int bytesRead);

                Dictionary<string, object> payload = claims.ToDictionary(k => k.Type, v => (object)v.Value);
                jwt = Jose.JWT.Encode(payload, rsa, Jose.JwsAlgorithm.RS256);
            }
            return jwt;
        }

0 个答案:

没有答案