【问题标题】:How to use APNs Auth Key (.p8 file) in C#?如何在 C# 中使用 APNs 身份验证密钥(.p8 文件)?
【发布时间】:2021-05-20 08:41:00
【问题描述】:

我正在尝试使用基于令牌的身份验证向 iOS 设备发送推送通知。

根据需要,我在 Apple 的 Dev Portal 中生成了一个 APNs Auth Key,并下载了它(这是一个扩展名为 p8 的文件)。

要从我的 C# 服务器发送推送通知,我需要以某种方式使用这个 p8 文件来签署我的 JWT 令牌。我该怎么做?

我尝试将文件加载到 X509Certificate2,但 X509Certificate2 似乎不接受 p8 文件,因此我尝试将文件转换为 pfx/p12,但找不到实际可行的方法。

【问题讨论】:

    标签: c# apple-push-notifications


    【解决方案1】:

    我找到了一种方法,使用BouncyCastle

    private static CngKey GetPrivateKey()
    {
        using (var reader = File.OpenText("path/to/apns/auth/key/file.p8"))
        {
            var ecPrivateKeyParameters = (ECPrivateKeyParameters)new PemReader(reader).ReadObject();
            var x = ecPrivateKeyParameters.Parameters.G.AffineXCoord.GetEncoded();
            var y = ecPrivateKeyParameters.Parameters.G.AffineYCoord.GetEncoded();
            var d = ecPrivateKeyParameters.D.ToByteArrayUnsigned();
            return EccKey.New(x, y, d);
        }
    }
    

    现在创建并签署令牌(使用jose-jwt):

    private static string GetProviderToken()
    {
        var epochNow = (int) DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).TotalSeconds;
        var payload = new Dictionary<string, object>()
        {
            {"iss", "your team id"},
            {"iat", epochNow}
        };
        var extraHeaders = new Dictionary<string, object>()
        {
            {"kid", "your key id"}
        };
        var privateKey = GetPrivateKey();
        return JWT.Encode(payload, privateKey, JwsAlgorithm.ES256, extraHeaders);
    }
    

    【讨论】:

    • 您愿意分享您用于上传令牌和有效负载数据的代码吗?我已经尝试了几个小时,但只收到“连接已关闭”错误。
    • 您好,如何使用此令牌调用 Apple 网络服务?
    • 您能否详细说明如何将帖子发送到 APN 服务?我的代码与下面线程中的代码非常相似,我得到了同样的错误。任何帮助将不胜感激。 stackoverflow.com/questions/53378912/…
    【解决方案2】:

    我希望这是一个解决方案;

    private static string GetToken(string fileName)
        {
            var fileContent = File.ReadAllText(fileName).Replace("-----BEGIN PRIVATE KEY-----", "").Replace
                ("-----END PRIVATE KEY-----", "").Replace("\r", "");
            
            var signatureAlgorithm = GetEllipticCurveAlgorithm(fileContent);
    
            ECDsaSecurityKey eCDsaSecurityKey = new ECDsaSecurityKey(signatureAlgorithm)
            {
                KeyId = "S********2"
            };
    
            var handler = new JwtSecurityTokenHandler();   
            JwtSecurityToken token = handler.CreateJwtSecurityToken(
                issuer: "********-****-****-****-************",
                audience: "appstoreconnect-v1",
                expires: DateTime.UtcNow.AddMinutes(5), 
                issuedAt: DateTime.UtcNow,
                notBefore: DateTime.UtcNow,
                signingCredentials: new SigningCredentials(eCDsaSecurityKey, SecurityAlgorithms.EcdsaSha256));
    
            return token.RawData;
    
        }
        
        private static ECDsa GetEllipticCurveAlgorithm(string privateKey)
        {
            var keyParams = (ECPrivateKeyParameters)PrivateKeyFactory.CreateKey(Convert.FromBase64String(privateKey));
    
            var normalizedEcPoint = keyParams.Parameters.G.Multiply(keyParams.D).Normalize();
    
            return ECDsa.Create(new ECParameters
            {
                Curve = ECCurve.CreateFromValue(keyParams.PublicKeyParamSet.Id),
                D = keyParams.D.ToByteArrayUnsigned(),
                Q =
                {
                    X = normalizedEcPoint.XCoord.GetEncoded(),
                    Y = normalizedEcPoint.YCoord.GetEncoded()
                }
            });
        }
    

    【讨论】:

    • 你能简要解释一下为什么这是一个解决方案吗?
    • 这对我来说可以连接到应用商店服务器 api !谢谢
    猜你喜欢
    • 1970-01-01
    • 2017-03-22
    • 2021-02-17
    • 2018-11-14
    • 2019-06-25
    • 1970-01-01
    • 2018-08-25
    • 2019-07-24
    • 1970-01-01
    相关资源
    最近更新 更多