java - 在 Java 中生成 VAPID key 并将其传递给 JavaScript PushManager

标签 java bouncycastle web-push ecdsa vapid

我正在尝试在我的应用程序中通过网络推送协议(protocol)使用网络推送通知。为了将 Push API 与 VAPID 结合使用,我需要一个 applicationServerKey

PushManager subscribe 方法采用 VAPID key (仅公钥)作为参数,并提供订阅端点和推送消息的 key 。

为了生成 VAPID key ,到目前为止,我一直在使用 node.js(google web-push 包)和 openssl 。但在我的用例中,VAPID key 应该在 Java 中生成并传递给 JavaScript 以从浏览器订阅。

我正在尝试使用下面的 Java 代码来生成 VAPID key 。我能够成功创建 key ,但是当我传递生成的公钥(base64 编码字符串)时,subscribe 方法返回一个错误:

Unable to register service worker. DOMException: Failed to execute 'subscribe' on 'PushManager': The provided applicationServerKey is not valid..

请帮我解决这个问题。下面是我的Java代码:

ECNamedCurveParameterSpec parameterSpec = 
ECNamedCurveTable.getParameterSpec("prime256v1");
KeyPairGenerator keyPairGenerator = 
KeyPairGenerator.getInstance("ECDH", "BC");
keyPairGenerator.initialize(parameterSpec);
KeyPair serverKey = keyPairGenerator.generateKeyPair();

PrivateKey priv = serverKey.getPrivate();
PublicKey pub = serverKey.getPublic();`
System.out.println(Base64.toBase64String(pub.getEncoded()));

最佳答案

请参阅以下链接以获取 MartijnDwars 的回答。 https://github.com/web-push-libs/webpush-java/issues/30

you can use Utils.savePublicKey to convert your Java-generated PublicKey to a byte[]. This byte[] is then passed to the PushManager.subscribe method.

It may be more convenient to base64 encode the byte[] in Java and base64 decode the string in JavaScript. For example, after generating the keypair in Java:

KeyPair keyPair = generateKeyPair();
byte[] publicKey = Utils.savePublicKey((ECPublicKey) keyPair.getPublic());
String publicKeyBase64 = BaseEncoding.base64Url().encode(publicKey);
System.out.println("PublicKey = " + publicKeyBase64);
// PublicKey = BPf36QAqZNNvvnl9kkpTDerXUOt6Nm6P4x9GEvmFVFKgVyCVWy24KUTs6wLQtbV2Ug81utbNnx86_vZzXDyrl88=

Then in JavaScript:

function subscribe() {
    const publicKey = base64UrlToUint8Array('BPf36QAqZNNvvnl9kkpTDerXUOt6Nm6P4x9GEvmFVFKgVyCVWy24KUTs6wLQtbV2Ug81utbNnx86_vZzXDyrl88=');

    navigator.serviceWorker.ready.then(function (serviceWorkerRegistration) {
        serviceWorkerRegistration.pushManager.subscribe({
            userVisibleOnly: true,
            applicationServerKey: publicKey
        })
        .then(function (subscription) {
            return sendSubscriptionToServer(subscription);
        })
        .catch(function (e) {
            if (Notification.permission === 'denied') {
                console.warn('Permission for Notifications was denied');
            } else {
                console.error('Unable to subscribe to push.', e);
            }
        });
    });
}

function base64UrlToUint8Array(base64UrlData) {
    const padding = '='.repeat((4 - base64UrlData.length % 4) % 4);
    const base64 = (base64UrlData + padding)
        .replace(/\-/g, '+')
        .replace(/_/g, '/');

    const rawData = atob(base64);
    const buffer = new Uint8Array(rawData.length);

    for (let i = 0; i < rawData.length; ++i) {
        buffer[i] = rawData.charCodeAt(i);
    }

    return buffer;
}

关于java - 在 Java 中生成 VAPID key 并将其传递给 JavaScript PushManager,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44149608/

相关文章:

java - 在 Java 8 中构建 Map 以进行集成测试的重构方法 - 函数式编程的机会?

java - 微服务之间的通信、共享实体或其他 hell

javascript - webpush,如果没有标签,如何打开窗口

web-push - Pushpad 或 Web 推送通知如何自定义对话框消息

java - 我需要 Java 扫描仪 'reset' 修复无效字符

java - 如何使用类名作为方法参数的类型

java - 向 PDF 添加时间戳会损坏文件

java - 为 SSL 通信创建证书

java - BouncyCaSTLe 在加密文件中自动附加签名

java - Vaadin 7 应用程序中推送的最小示例 ("@Push")