如何为 APN 标记化(.NET、C#)编码 JWT

Posted

技术标签:

【中文标题】如何为 APN 标记化(.NET、C#)编码 JWT【英文标题】:How to encode JWT for APN tokenization (.NET, C#) 【发布时间】:2017-06-03 00:49:44 【问题描述】:

我正在尝试通过标记化向 APN 发送推送通知。我尝试使用 jose-jwt 和 Microsot Jwt 类等一些库来创建 JWT 令牌,但我无法理解它。

我无法创建 JWT 并使用私钥对其进行签名。

为了与证书通信,我使用了 PushSharp,它工作得很好。任何人都可以帮助我使用类似的示例但使用令牌吗?

编辑:在此处遵循 Apple 的文档:https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CommunicatingwithAPNs.html#//apple_ref/doc/uid/TP40008194-CH11-SW1

示例代码:我最接近的东西看起来像这样,但我不知道如何正确创建 CngKey

var payload = new Dictionary<string, object>()
            
                 "iss", issuer ,
                 "iat", DateTime.UtcNow 
            ;

var headers = new Dictionary<string, object>()
            
                  "kid", keyIdentifier
            ;

CngKey key = CngKey.Create(CngAlgorithm.ECDsaP256); //how to create this CngKey

string token = Jose.JWT.Encode(payload, key, JwsAlgorithm.ES256, headers);

【问题讨论】:

你能提供一些代码让我们看看吗?既然您问的是一般性问题,我建议您阅读以下内容:stormpath.com/blog/token-authentication-asp-net-core 谢谢,我会调查的。添加了一个代码示例,显示了我卡在哪里。 【参考方案1】:

这是我使用的:

var privateKeyContent = System.IO.File.ReadAllText(AUTHKEYFILE);
var privateKey = privateKeyContent.Split('\n')[1];
var secretKeyFile = Convert.FromBase64String(privateKey);
var secretKey = CngKey.Import(secretKeyFile,CngKeyBlobFormat.Pkcs8PrivateBlob);

【讨论】:

感谢您的回答,已经有了解决方案。刚加了。也许你可以使用它。 运行您的代码我收到:'System.Core.dll 中发生'System.Security.Cryptography.CryptographicException' 类型的未处理异常' 这是p8 文件...有什么问题? 由于CngKey.Import,这将无法在非 Windows 上运行【参考方案2】:

感谢您的回答,必须联系许多支持人员才能完成此操作。这是最终结果的样子。

/// <summary>
    /// Method returns ECDSA signed JWT token format, from json header, json payload and privateKey (pure string extracted from *.p8 file - PKCS#8 format)
    /// </summary>
    /// <param name="privateKey">ECDSA256 key</param>
    /// <param name="header">JSON header, i.e. "\"alg\":\"ES256\" ,\"kid\":\"1234567899"\""</param>
    /// <param name="payload">JSON payload, i.e.  \"iss\":\"MMMMMMMMMM"\",\"iat\":"122222222229""</param>
    /// <returns>base64url encoded JWT token</returns>
    public static string SignES256(string privateKey, string header, string payload)
    
        CngKey key = CngKey.Import(
            Convert.FromBase64String(privateKey), 
            CngKeyBlobFormat.Pkcs8PrivateBlob);

        using (ECDsaCng dsa = new ECDsaCng(key))
        
            dsa.HashAlgorithm = CngAlgorithm.Sha256;
            var unsignedJwtData = 
                Url.Base64urlEncode(Encoding.UTF8.GetBytes(header)) + "." + Url.Base64urlEncode(Encoding.UTF8.GetBytes(payload));
            var signature = 
                dsa.SignData(Encoding.UTF8.GetBytes(unsignedJwtData));
            return unsignedJwtData + "." + Url.Base64urlEncode(signature);
        
    

【讨论】:

您能评论一下您为使其正常工作所做的工作吗?并说明您在哪里找到了所需的答案(如果不在此处)。 Jose-jwt 论坛和 Apple 支持。我缺少上面的 Base64 编码以使其正常工作。苹果人最终用他们的提示塑造了上面的代码。我在 C# 中找不到任何工作示例的官方文档。 关于您如何将通知实际发送到 Apple 服务器的任何提示?我已经尝试了很多事情来让它工作,但没有运气。如果您有任何代码,将不胜感激! @Brad C - 使用 HTTP/2 客户端 @user3790083 如何从 p8 文件中提取私钥?!谢谢!【参考方案3】:

这是我使用的;

public static string getAppleJWT(string privateKeyPath, string teamId, string keyId)


    var private_key = getPrivateKey(privateKeyPath);

    var utc0 = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
    var issueTime = DateTime.Now;

    var payload = new Dictionary<string, object>()
        
             "iss", teamId ,
             "iat", (int)issueTime.Subtract(utc0).TotalSeconds 
        ;

    var headers = new Dictionary<string, object>()
        
              "alg", "ES256",
              "kid", keyId
        ;


    return Jose.JWT.Encode(payload, private_key, JwsAlgorithm.ES256, headers);


public static CngKey getPrivateKey(string privateKeyPath)

    var privateKeyLines = System.IO.File.ReadAllLines(privateKeyPath).ToList();
    privateKeyLines.RemoveAt(privateKeyLines.Count - 1);
    privateKeyLines.RemoveAt(0);

    var privateKey = string.Join("", privateKeyLines);
    var secretKeyFile = Convert.FromBase64String(privateKey);
    var secretKey = CngKey.Import(secretKeyFile, CngKeyBlobFormat.Pkcs8PrivateBlob);
    return secretKey;

【讨论】:

以上是关于如何为 APN 标记化(.NET、C#)编码 JWT的主要内容,如果未能解决你的问题,请参考以下文章

有关如何在 c# 中为 Windows 7 任务栏编码所需的信息

如何为 MSMQ 创建 C# 侦听器服务作为 Windows 服务

如何为 C# 项目生成 .tlh 文件

如何为 XSLT 代码片段配置 CruiseControl 的 C# 版本?

asp.net MVC 如何为一个视图中某个表单(Form)指定某个提交方法(如CreateRole)

如何为 ASP.net/C# 应用程序配置文件值中的值添加与号