Websocket能携带token过去后端吗

要将 token 传递给 WebSocket,有以下几种常见方法:

方法一:在 WebSocket URL 中添加 token 参数(推荐)

修改 WebSocket URL,将 token 作为查询参数传递:

javascript 复制代码
// 在创建 WebSocket 连接时,将 token 添加到 URL 中
const token = 'your-token-here'; // 从你的 auth 模块获取 token
ws.value = new WebSocket(`${wsUrl.value}?token=${encodeURIComponent(token)}`);

完整的修改示例:

javascript 复制代码
const initWebSocket = () => {
  if (ws.value && ws.value.readyState === WebSocket.OPEN) {
    ws.value.close();
  }
  
  // 获取 token(从你的 auth 模块获取)
  const token = getToken(); // 假设你有 getToken() 函数
  
  try {
    // 将 token 添加到 URL 中
    const fullWsUrl = `${wsUrl.value}?token=${encodeURIComponent(token)}`;
    ws.value = new WebSocket(fullWsUrl);
    
    console.log('ws', ws.value);

    ws.value.onopen = () => {
      console.log('WebSocket 连接成功');
    };

    // ... 其他事件处理代码保持不变
  } catch (err) {
    console.log('initWebSocket error', err);
  }
};

方法二:通过 HTTP 头部传递(需要服务器支持)

如果服务器支持通过 HTTP 头部验证,可以使用以下方式(需要使用 ReconnectingWebSocket 库或自定义实现):

javascript 复制代码
// 需要先安装:npm install reconnecting-websocket
import ReconnectingWebSocket from 'reconnecting-websocket';

const token = getToken();
const rws = new ReconnectingWebSocket(wsUrl.value, [], {
  connectionTimeout: 10000,
  maxRetries: 3,
  headers: {
    'Authorization': `Bearer ${token}`,
    // 或者
    'X-Auth-Token': token
  }
});

方法三:连接建立后立即发送认证消息

在 WebSocket 连接建立后,立即发送包含 token 的认证消息:

javascript 复制代码
ws.value.onopen = () => {
  console.log('WebSocket 连接成功');
  
  // 连接建立后立即发送认证消息
  const token = getToken();
  const authMessage = {
    type: 'auth',
    token: token
  };
  ws.value.send(JSON.stringify(authMessage));
};

推荐实现

结合代码,推荐使用方法一,因为实现简单且服务器通常支持:

javascript 复制代码
const initWebSocket = () => {
  if (ws.value && ws.value.readyState === WebSocket.OPEN) {
    ws.value.close();
  }
  
  try {
    // 从你的 auth 模块获取 token
    const token = getToken();
    
    // 将 token 添加到 WebSocket URL 中
    const fullWsUrl = token 
      ? `${wsUrl.value}?token=${encodeURIComponent(token)}` 
      : wsUrl.value;
    
    ws.value = new WebSocket(fullWsUrl);
    console.log('ws', ws.value);

    ws.value.onopen = () => {
      console.log('WebSocket 连接成功');
    };

    ws.value.onmessage = (e) => {
      // ... 你现有的消息处理代码
    };

    ws.value.onclose = () => {
      console.log('连接已关闭');
    };
  } catch (err) {
    console.log('initWebSocket error', err);
  }
};

注意事项

  1. URL 编码 :使用 encodeURIComponent() 确保 token 中的特殊字符被正确编码
  2. 安全性:URL 中的 token 可能会被记录在服务器日志中,如果安全性要求很高,建议使用方法三
  3. 服务器支持:确保你的后端服务器能够从 URL 参数中读取并验证 token

验证是否成功

你可以在浏览器开发者工具的 Network 标签中查看 WebSocket 连接,确认 URL 中包含了 token 参数。

这样修改后,你的 WebSocket 连接就会携带 token,服务器端可以根据这个 token 进行身份验证。

扩展:

token不放在url,放在header头部,Authorization Bearer + token

由于 WebSocket 不支持直接设置 HTTP 头部,以下是几种解决方案:

方法一:连接建立后立即发送认证消息(推荐)

这是最常用和安全的方式,不会暴露 token 在 URL 中:

javascript 复制代码
const initWebSocket = () => {
  if (ws.value && ws.value.readyState === WebSocket.OPEN) {
    ws.value.close();
  }
  
  const token = `Bearer eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6ImZjZTFjZWQ5LTM0ODYtNGQ5Yy05Y2Q4LTI2YzliMzI0MWFjYyJ9.PVvyxvNINiucOZuFadHMaL-7K7hwzeQX9aVpAciNRLMyLGcF7ajKZ3nhKUM6v0rXY8E552_UnCOjp6EA5HrsWw`;
  
  try {
    // 不在 URL 中传递 token
    ws.value = new WebSocket(wsUrl.value);
    console.log('ws', ws.value);

    ws.value.onopen = () => {
      console.log('WebSocket 连接成功');
      
      // 连接建立后立即发送认证消息
      const authMessage = {
        type: 'auth',
        token: token
      };
      ws.value.send(JSON.stringify(authMessage));
    };

    ws.value.onmessage = (e) => {
      // 检查是否是认证响应
      if (e.data && typeof e.data === 'string') {
        try {
          const res = JSON.parse(e.data);
          if (res.type === 'auth_response') {
            if (res.success) {
              console.log('WebSocket 认证成功');
            } else {
              console.error('WebSocket 认证失败:', res.message);
              ws.value.close();
            }
            return;
          }
        } catch (error) {
          // 如果不是 JSON 格式的消息,继续处理其他消息
        }
      }
      
      // 你现有的消息处理代码
      if (e.data === 'DONE') {
        console.log('结束信号');
        ws.value.close();
        return;
      }
      
      // ... 其他消息处理逻辑保持不变
      const res = JSON.parse(e.data);
      // ... 你的现有处理逻辑
    };

    ws.value.onclose = () => {
      console.log('连接已关闭');
    };
    
    ws.value.onerror = (error) => {
      console.error('WebSocket 错误:', error);
    };
  } catch (err) {
    console.log('initWebSocket error', err);
  }
};

方法二:使用第三方库(需要安装)

如果你的服务器支持,可以使用 reconnecting-websocket 库:

javascript 复制代码
npm install reconnecting-websocket
javascript 复制代码
import ReconnectingWebSocket from 'reconnecting-websocket';

const initWebSocket = () => {
  if (ws.value) {
    ws.value.close();
  }
  
  const token = `Bearer eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6ImZjZTFjZWQ5LTM0ODYtNGQ5Yy05Y2Q4LTI2YzliMzI0MWFjYyJ9.PVvyxvNINiucOZuFadHMaL-7K7hwzeQX9aVpAciNRLMyLGcF7ajKZ3nhKUM6v0rXY8E552_UnCOjp6EA5HrsWw`;
  
  const rws = new ReconnectingWebSocket(wsUrl.value, [], {
    connectionTimeout: 10000,
    maxRetries: 3,
    WebSocket: class extends WebSocket {
      constructor(url) {
        super(url);
        // 设置自定义头部(需要服务器支持)
        this.protocol = token; // 这个方式可能不被所有服务器支持
      }
    }
  });
  
  ws.value = rws;
  
  // ... 其他事件处理保持不变
};

方法三:使用你的 auth 模块获取 token

从你的代码中看到你有 getToken 函数,建议使用它:

javascript 复制代码
import { getToken } from '@/package/utils/auth';

const initWebSocket = () => {
  if (ws.value && ws.value.readyState === WebSocket.OPEN) {
    ws.value.close();
  }
  
  // 从 auth 模块获取 token
  const token = getToken();
  if (!token) {
    console.error('未获取到 token,无法建立 WebSocket 连接');
    return;
  }
  
  const fullToken = `Bearer ${token}`;
  
  try {
    ws.value = new WebSocket(wsUrl.value);
    console.log('ws', ws.value);

    ws.value.onopen = () => {
      console.log('WebSocket 连接成功');
      
      // 发送认证消息
      const authMessage = {
        type: 'auth',
        token: fullToken
      };
      ws.value.send(JSON.stringify(authMessage));
    };

    // ... 其他处理逻辑保持不变
  } catch (err) {
    console.log('initWebSocket error', err);
  }
};

完整的推荐实现

javascript 复制代码
import { ref, reactive, watch, onUnmounted, onMounted, nextTick } from 'vue';
import { CircleCloseFilled, Top } from '@element-plus/icons-vue';
import { BubbleList, Sender, Typewriter } from 'vue-element-plus-x';
import { getToken } from '@/package/utils/auth'; // 导入你的 auth 模块

// ... 其他代码保持不变

const initWebSocket = () => {
  if (ws.value && ws.value.readyState === WebSocket.OPEN) {
    ws.value.close();
  }
  
  // 从 auth 模块获取 token
  const token = getToken();
  if (!token) {
    console.error('未获取到 token,无法建立 WebSocket 连接');
    return;
  }
  
  const fullToken = `Bearer ${token}`;
  
  try {
    ws.value = new WebSocket(wsUrl.value);
    console.log('ws', ws.value);

    ws.value.onopen = () => {
      console.log('WebSocket 连接成功');
      
      // 发送认证消息
      const authMessage = {
        type: 'auth',
        token: fullToken
      };
      ws.value.send(JSON.stringify(authMessage));
    };

    ws.value.onmessage = (e) => {
      // 首先检查是否是认证响应
      if (e.data && typeof e.data === 'string') {
        try {
          const res = JSON.parse(e.data);
          
          // 如果是认证响应
          if (res.type === 'auth_response') {
            if (res.success) {
              console.log('WebSocket 认证成功');
            } else {
              console.error('WebSocket 认证失败:', res.message);
              ws.value.close();
            }
            return;
          }
        } catch (error) {
          // 如果不是 JSON 格式的消息,继续处理其他消息
        }
      }
      
      // 原有的消息处理逻辑
      if (e.data === 'DONE') {
        console.log('结束信号');
        ws.value.close();
        return;
      }
      
      console.log('接收data:', e.data);
      const res = JSON.parse(e.data);
      const msgIndex = res.index;
      if (msgIndex >= 0 && msgIndex < dataList.value.length) {
        const message = dataList.value[msgIndex];
        console.log('message', message);
        if (message) {
          switch (res.type) {
            case 'ai_response':
              message.aiAnswer += res.content;
              message.status = 'done';
              break;

            case 'ai_stream':
              message.aiAnswer += res.chunk;
              message.status = 'streaming';
              break;

            case 'error':
              message.aiAnswer = `[Error] ${res.msg}`;
              message.status = 'error';
              break;
          }
        }
      }

      nextTick(() => {
        scrollToBottom();
      });
      console.log('dataList.value', dataList.value);
    };

    ws.value.onclose = () => {
      console.log('连接已关闭');
    };
    
    ws.value.onerror = (error) => {
      console.error('WebSocket 错误:', error);
    };
  } catch (err) {
    console.log('initWebSocket error', err);
  }
};

// ... 其他代码保持不变

重要提醒

  1. 服务器支持:确保你的后端 WebSocket 服务器支持接收认证消息并验证 token
  2. 安全考虑:使用认证消息的方式比在 URL 中传递 token 更安全,因为不会在服务器日志中暴露 token
  3. 错误处理:添加认证失败的处理逻辑,及时关闭连接避免资源浪费

这是处理 WebSocket 认证的最佳实践方式。

相关推荐
AAA阿giao2 小时前
从零拆解一个 React + TypeScript 的 TodoList:模块化、数据流与工程实践
前端·react.js·ui·typescript·前端框架
杨超越luckly2 小时前
HTML应用指南:利用GET请求获取中国500强企业名单,揭秘企业增长、分化与转型的新常态
前端·数据库·html·可视化·中国500强
一 乐2 小时前
校园二手交易|基于springboot + vue校园二手交易系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端
80530单词突击赢2 小时前
SpringBoot整合SpringMVC全解析
java·spring boot·后端
hedley(●'◡'●)2 小时前
基于cesium和vue的大疆司空模仿程序
前端·javascript·vue.js·python·typescript·无人机
qq5_8115175152 小时前
web城乡居民基本医疗信息管理系统信息管理系统源码-SpringBoot后端+Vue前端+MySQL【可直接运行】
前端·vue.js·spring boot
百思可瑞教育2 小时前
构建自己的Vue UI组件库:从设计到发布
前端·javascript·vue.js·ui·百思可瑞教育·北京百思教育
百锦再2 小时前
Vue高阶知识:利用 defineModel 特性开发搜索组件组合
前端·vue.js·学习·flutter·typescript·前端框架
hdsoft_huge2 小时前
1panel面板中部署SpringBoot和Vue前后端分离系统 【图文教程】
vue.js·spring boot·后端