You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于localStorage与Websocket的自动授权实现技术咨询

WebSocket自动授权:JS客户端 + Go服务器常见问题与解决方案

Hey there! 既然你已经基于推荐的技术文章在JS单页应用和Go后端之间搭建了WebSocket自动授权的基础框架,我整理了这个场景下最容易遇到的几个问题和对应的解决方案,希望能帮到你:

1. 如何在WebSocket握手阶段安全传递授权凭证?

WebSocket的握手过程本质是HTTP请求,我们可以利用这个阶段传递授权信息,推荐两种兼容且安全的方式:

客户端(JS)实现

// 方式1:URL参数传递(兼容性更强,注意对token编码避免特殊字符)
const authToken = localStorage.getItem('user-auth-token');
const socket = new WebSocket(`wss://your-server-domain/ws?token=${encodeURIComponent(authToken)}`);

// 方式2:自定义请求头传递(需确保Go后端配置CORS允许该头)
// 注:原生WebSocket API无法直接设置自定义头,可借助第三方库如`websocket`实现

服务器端(Go)实现

var upgrader = websocket.Upgrader{
    CheckOrigin: func(r *http.Request) bool {
        // 严格校验请求Origin,只允许信任的前端域名
        return r.Header.Get("Origin") == "https://your-frontend-domain"
    },
}

func handleWebSocket(w http.ResponseWriter, r *http.Request) {
    // 从URL参数获取token
    token := r.URL.Query().Get("token")
    // 或从请求头获取(如果用自定义头方案)
    // token := r.Header.Get("X-Auth-Token")

    // 验证token有效性(替换为你的实际验证逻辑,比如JWT解析)
    claims, err := validateJWTToken(token)
    if err != nil || claims == nil {
        http.Error(w, "Unauthorized", http.StatusUnauthorized)
        return
    }

    // 升级HTTP连接为WebSocket
    conn, err := upgrader.Upgrade(w, r, nil)
    if err != nil {
        log.Printf("Failed to upgrade WebSocket: %v", err)
        return
    }
    // 后续维护连接、处理消息逻辑...
}

2. Token过期后如何自动重新授权并恢复连接?

当服务器检测到Token过期时,主动返回自定义关闭码,客户端监听该事件后自动刷新Token并重连:

客户端(JS)实现

function initWebSocket() {
    const authToken = localStorage.getItem('user-auth-token');
    const socket = new WebSocket(`wss://your-server-domain/ws?token=${encodeURIComponent(authToken)}`);

    socket.onclose = (event) => {
        // 自定义关闭码4001表示Token过期
        if (event.code === 4001) {
            // 调用后端刷新Token接口
            fetch('/api/refresh-token', {
                method: 'POST',
                credentials: 'include' // 若用Cookie存储RefreshToken则开启
            })
            .then(res => {
                if (!res.ok) throw new Error('Refresh token failed');
                return res.json();
            })
            .then(data => {
                localStorage.setItem('user-auth-token', data.newAccessToken);
                // 1秒后重连,避免频繁请求
                setTimeout(initWebSocket, 1000);
            })
            .catch(err => {
                // 刷新失败,跳转到登录页
                window.location.href = '/login';
            });
        }
    };

    socket.onmessage = (event) => {
        // 处理服务器推送的消息
        console.log('Received message:', event.data);
    };
}

// 初始化连接
initWebSocket();

服务器端(Go)实现

func (client *WebSocketClient) readMessages() {
    defer func() {
        client.hub.unregister <- client
        client.conn.Close()
    }()

    for {
        _, _, err := client.conn.ReadMessage()
        if err != nil {
            // 检测Token是否过期(替换为你的实际过期检查逻辑)
            if isTokenExpired(client.token) {
                // 发送自定义关闭消息
                closeMsg := websocket.FormatCloseMessage(4001, "Access token expired")
                client.conn.WriteMessage(websocket.CloseMessage, closeMsg)
            }
            if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway) {
                log.Printf("WebSocket error: %v", err)
            }
            break
        }
        // 正常处理消息逻辑...
    }
}

3. 如何提升授权流程的安全性?

  • 强制使用WSS:永远用wss://(WebSocket over TLS)代替ws://,确保所有传输数据加密。
  • 避免URL传递敏感信息:虽然WSS会加密URL,但服务器日志可能记录完整URL,优先用请求头传递Token。
  • 短有效期AccessToken:将AccessToken有效期设置为15-30分钟,配合长有效期RefreshToken,降低泄露风险。
  • 严格Origin校验:在Go后端的CheckOrigin函数中只允许信任的前端域名建立连接,防止跨域恶意请求。

内容的提问来源于stack exchange,提问作者hewiefreeman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 12:19:00