如何从扩展的后台脚本在 websocket 连接中发送 cookie?

How to send cookies in websocket connection from extension's background script?

我正在尝试从 chrome 扩展打开一个经过身份验证的 websocket 连接到我的后端,因为我正在使用会话 cookie。这是我的清单文件:

{
    "manifest_version": 2,
    "background": {
        "scripts": ["extension.js"],
        "persistent": true
    },
    "permissions": [
        "tabs",
        "storage",
        "http://localhost:8000/",
        "ws://localhost:8000/"
    ],
    "icons": {
        "16": "img/icon16.png",
        "48": "img/icon48.png",
        "128": "img/icon128.png"
    }
}

我请求允许在 HTTP 和 websocket 方案上访问 localhost:8000,但是 Chrome 只为 AJAX 请求发送 cookie。如果我尝试

await fetch('http://localhost:8000/checklogin', {
    method: 'GET',
    credentials: 'include'
});

从后台脚本发送 cookie,但如果我尝试

const ws = new WebSocket('ws://localhost:8000/');

根本没有发送 cookie。

不是同一个域,为什么 Chrome 没有为 websocket 发送 cookie?

根据我的研究,我得出结论 chrome 扩展不支持带有 websocket 凭据的 CORS,因此 Chrome 不会在 websocket 升级请求中注入凭据。解决方法是使用 chrome.webRequest 拦截 websocket 升级请求并注入 Cookie header:

class WebsocketCookie {

    constructor(websocketUrl, name, value) {
        this.name = name;
        this.value = value;
        chrome.webRequest.onBeforeSendHeaders.addListener(
            ({ requestHeaders }) => {
                requestHeaders.push({name: 'Cookie', value: `${this.name}=${this.value}`});
                return {requestHeaders};
            },
            {types: ['websocket'], urls: [websocketUrl]},
            ['blocking', 'requestHeaders', 'extraHeaders']
        );
    }
}

// you can change this cookie later by changing cookie.name or cookie.value
const cookie = new WebsocketCookie('ws://localhost:8000/', 'sessionid', 'my_session_id');
const ws = new WebSocket('ws://localhost:8000/'); // sessionid cookie will be injected

需要将 websocket URL、webRequestwebRequestBlocking 权限添加到清单文件。使用 chrome.cookies 获取您需要在 websocket 升级请求中注入的 cookie。

如果您想提高安全性,onBeforeSendHeaders callback takes the origin of that request as initiator member, use that to check if origin is your own extension. You can get your extension's origin using chrome.management API。