Files
lmvpn_server/internal/vpn/handler.go
T
kevin 8398067acb feat: 连接列表显示客户端真实 IP,支持反代和 CDN 场景
新增可配置的 real_ip_headers(默认 CF-Connecting-IP > X-Real-IP >
X-Forwarded-For 降级取值),trusted_proxies 用于 gin 代理信任链。
WebSocket 连接建立时捕获真实 IP 并在 /profile 和 /admin 连接列表展示,
登录会话 IP 同步改用真实 IP。
2026-07-10 16:58:14 +08:00

71 lines
1.4 KiB
Go

package vpn
import (
"log"
"net/http"
"net/url"
"lmvpn/internal/db"
"lmvpn/internal/middleware"
"lmvpn/internal/model"
"github.com/gin-gonic/gin"
"github.com/gorilla/websocket"
)
var upgrader = websocket.Upgrader{
ReadBufferSize: 4096,
WriteBufferSize: 4096,
CheckOrigin: func(r *http.Request) bool {
origin := r.Header.Get("Origin")
if origin == "" {
return true
}
u, err := url.Parse(origin)
if err != nil {
return false
}
return u.Host == r.Host
},
}
func HandleWS(c *gin.Context) {
tokenStr := c.Query("token")
realIP := middleware.GetRealIP(c)
conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
if err != nil {
log.Printf("WebSocket 升级失败: %v", err)
return
}
if tokenStr != "" {
claims, err := middleware.ParseToken(tokenStr)
if err != nil {
sendJSON(conn, authResponse{Type: "auth_err", Message: "令牌无效或已过期"})
conn.Close()
return
}
var u model.User
if err := db.DB.First(&u, claims.UserID).Error; err != nil || u.Status != 1 {
sendJSON(conn, authResponse{Type: "auth_err", Message: "用户不存在或已禁用"})
conn.Close()
return
}
runTunnel(conn, &u, realIP)
return
}
user, err := authenticate(conn, db.DB, realIP)
if err != nil {
log.Printf("认证读取失败: %v", err)
conn.Close()
return
}
if user == nil {
return
}
runTunnel(conn, user, realIP)
}