我的项目中使用的websocket 即时通讯一直没有加权限验证功能,就是简单的连接后发消息,但是最近面试的时候有人问我websocket如何鉴权,现在把这个漏洞补上
关键步奏:在第一次建立连接的时候前端需要带上token,没有token或者token失效都会连接失败,建立连接后就是长连接了,只需要验证一次就可以了
这是后端代码 go语言
路由代码
defaultRoutes.GET("/ws", func(ctx *gin.Context) {
t := ctx.Query("token")
token, _, err := middlewares.ParseToken(t)
if err != nil || !token.Valid {
ctx.JSON(400, gin.H{
"message": "token无效",
})
} else {
controllers.UserController{}.WS(ctx.Writer, ctx.Request)
}
})
websocket连接
var upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
return true
},
}
var conns []*websocket.Conn
func (this UserController) WS(w http.ResponseWriter, r *http.Request) {
c, err := upgrader.Upgrade(w, r, nil)
if err != nil {
println("upgrade错误:", err)
return
}
defer c.Close()
conns = append(conns, c)
for {
_, _, err := c.ReadMessage()
if err != nil {
println("read:", err)
break
}
}
}
下面是前端代码
let token=sessionStorage.getItem("token")
const env = process.env.NODE_ENV
const url = env == 'development' ? "ws://127.0.0.1:8088/ws?token=" + token : "ws://m.liyefeng.top/ws?token=" + token
let websocket = null;
let socketState = ref(false); // 初始状态建议设为 false,等 onopen 再变 true
let isReconnecting = false; // 核心标志位:防止并发重连
let reconnectTimer = null; // 定时器引用,方便清理
const connect=()=> {
if (isReconnecting) return; // 如果正在重连,直接返回
websocket = new WebSocket(url);
websocket.onopen = (evt) => {
console.log("链接成功");
socketState.value = true;
isReconnecting = false; // 连接成功后重置标志位
// 清除可能存在的重连定时器
if (reconnectTimer) clearTimeout(reconnectTimer);
};
websocket.onmessage = (evt) => {
if (evt.data == "jianli") {
refreshChartJL();
} else if (evt.data == "music") {
refreshChartMusic();
}
};
websocket.onclose = () => {
console.log("链接关闭");
socketState.value = false;
isReconnecting = false;
attemptReconnect(); // 触发重连尝试
};
websocket.onerror = (err) => {
console.error("WebSocket发生错误:", err);
websocket.close(); // 主动关闭以触发 onclose 进入重连流程
};
}
const attemptReconnect=()=> {
// 如果没有 token(比如用户已退出登录),则不再重连
if (!sessionStorage.getItem("token")) return;
if (websocket && !isReconnecting && !reconnectTimer) {
isReconnecting = true;
console.log("准备在 3秒 后重新连接...");
reconnectTimer = setTimeout(() => {
reconnectTimer = null;
isReconnecting = false;
connect(); // 重新调用连接函数
}, 3000); // 3秒重连间隔
}
}
// 不能忘记在页面销毁前清空定时器和ws对象
2026年更新前端代码,加入了断开链接自动重连