java - 从 Java 6 升级到 Java 7/8 后,Apple 无法推送

标签 java ios push-notification apple-push-notifications

我正在将通过 APNS 向 Apple 设备发送推送通知的应用程序从 Java 6 升级到 Java 8。

当使用相同的 PKCS12 证书文件在 Java 8 上运行在 Java 6 下工作的相同 JAR 时,如果我尝试发送推送,我会返回状态代码 8(无效 token )。

这可能是什么原因造成的?

最佳答案

此问题是由 PKCS12 文件的内容和 Java 将 PKCS12 文件读入 Java 6 和 7 之间的 KeyStore 对象的方式的变化共同引起的。

在有问题的 pkcs12 文件上运行 openssl pkcs12 -in filename 会产生以下结果:

Enter Import Password:
MAC verified OK
Bag Attributes
    friendlyName: Apple Development IOS Push Services: app.id.1
    localKeyID: .... snip ....
subject=/UID=app.id.1/CN=Apple Development IOS Push Services: app.id.1/OU=PRXXXXXXXX/C=US
issuer=/C=US/O=Apple Inc./OU=Apple Worldwide Developer Relations/CN=Apple Worldwide Developer Relations Certification Authority
-----BEGIN CERTIFICATE-----
... snip ...
-----END CERTIFICATE-----
Bag Attributes
    friendlyName: Apple Development IOS Push Services: app.id.2
    localKeyID: .... snip ....
subject=/UID=app.id.2/CN=Apple Development IOS Push Services: app.id.2/OU=PRXXXXXXXX/C=US
issuer=/C=US/O=Apple Inc./OU=Apple Worldwide Developer Relations/CN=Apple Worldwide Developer Relations Certification Authority
-----BEGIN CERTIFICATE-----
... snip ...
-----END CERTIFICATE-----
Bag Attributes
    friendlyName: User Name
    localKeyID: ... snip ...
Key Attributes: <No Attributes>
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----BEGIN ENCRYPTED PRIVATE KEY-----
... snip ...
-----END ENCRYPTED PRIVATE KEY-----
Bag Attributes
    friendlyName: User Name
    localKeyID: ... snip ...
Key Attributes: <No Attributes>
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----BEGIN ENCRYPTED PRIVATE KEY-----
... snip ...
-----END ENCRYPTED PRIVATE KEY-----

您可以在这里看到 PKCS12 文件包含 2 个证书和 2 个私钥(实际上是同一个 key 的 2 个副本),每个对应一个不同的 App ID。列出的第一个是预期的应用程序 ID,而第二个是我们使用的不同应用程序。

此文件被读入 KeyStore,随后传递给 SSLSocket 以连接到 Apple。这是按如下方式完成的:

    String password = "my_password";
    KeyStore.ProtectionParameter pwParam = new KeyStore.PasswordProtection(password.toCharArray());
    KeyStore keystore = KeyStore.getInstance("PKCS12");
    System.out.println("keystore classname: " + keystore.getClass().getName());
    FileInputStream fileStream = new FileInputStream("certificate_file.p12");
    keystore.load(fileStream, password.toCharArray());
    for (Enumeration<String> e = keystore.aliases(); e.hasMoreElements(); ) {
            String alias = e.nextElement();
            System.out.println("*** entry name: " + alias);
            KeyStore.Entry entry = keystore.getEntry(alias, pwParam);
            System.out.println("entry as string: " + entry.toString());
            for (Certificate cert: keystore.getCertificateChain(alias)) {
                    System.out.println("*** cert: " + cert);
            }
    }

在 Java 6 下,运行上面的代码会得到以下结果:

keystore classname: java.security.KeyStore
*** entry name: User Name
entry as string: Private key entry and certificate chain with 1 elements:
[
[
  Version: V3
  Subject: C=US, OU=PRXXXXXXXX, CN=Apple Development IOS Push Services: app.id.1, UID=app.id.1

....

在 Java 7 或 8 下,我们得到这个:

keystore classname: java.security.KeyStore
*** entry name: User Name
entry as string: Private key entry and certificate chain with 1 elements:
[
[
  Version: V3
  Subject: C=US, OU=PRXXXXXXXX, CN=Apple Development IOS Push Services: app.id.2, UID=app.id.2

因此,因为两个证书引用相同的私钥,一个会覆盖另一个,因此 KeyStore 仅包含两个证书之一。在 Java 6 下,第一个证书被保留,而 Java 7 和 8 保留了第二个证书。因此,当连接到 Apple 时,它​​会发送错误的证书,并且发送的任何推送都被视为无效,因为发送的推送 token 的 App ID 与用于连接的证书的 App ID 不匹配。

要解决此问题,应仅使用预期的 App ID 生成 PKCS12 文件。这可确保读取并随后使用正确的证书连接到 Apple。

关于java - 从 Java 6 升级到 Java 7/8 后,Apple 无法推送,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37327551/

相关文章:

android - 无法使用适用于 Android 的 Google Cloud Messaging(不是帮助程序库)接收消息

Azure 移动服务(推送通知)

java - LuaJ(Java Lua库): Calling Lua functions in other files from a Lua file

iphone - 将图像添加到 MapView 注释

iOS 网络/ native 应用程序 Facebook 登录弹出窗口 - 失败?

ios - 观察异步请求

asp.net - 来自 ASP.net rest API 的 Flutter 推送通知

java - 对于基于输入标签的 DevExpress 下拉编辑器,在 selenium 中看不到任何输入命令

Java 8 Stream如何使用自定义逻辑合并2个大小不等的列表以选择重复项

Java 方法错误地在 kotlin 中自动重载