فهرست منبع

处理websocket header的问题

zhou.xiaoning 2 سال پیش
والد
کامیت
471268a2d9
3فایلهای تغییر یافته به همراه71 افزوده شده و 16 حذف شده
  1. 1 0
      initialize/router.go
  2. 9 3
      router/quote.go
  3. 61 13
      service/quote/quote.go

+ 1 - 0
initialize/router.go

@@ -39,6 +39,7 @@ func Routers() *gin.Engine {
 			router.InitMQPublicRouter(publicGroup)
 		}
 		router.InitAccountPublicRouter(publicGroup)
+		router.InitQuotePublicRouter(publicGroup)
 	}
 
 	// 鉴权组

+ 9 - 3
router/quote.go

@@ -6,10 +6,16 @@ import (
 	"github.com/gin-gonic/gin"
 )
 
+func InitQuotePublicRouter(r *gin.RouterGroup) {
+	quoteR := r.Group("Quote").Use()
+	{
+		quoteR.GET("WS", quote.Quote)
+	}
+}
+
 func InitQuotePrivateRouter(r *gin.RouterGroup) {
-	mqR := r.Group("Quote").Use()
+	quoteR := r.Group("Quote").Use()
 	{
-		mqR.GET("WS", quote.Quote)
-		mqR.POST("QuoteSubscribe", quote.QuoteSubscribe)
+		quoteR.POST("QuoteSubscribe", quote.QuoteSubscribe)
 	}
 }

+ 61 - 13
service/quote/quote.go

@@ -5,7 +5,9 @@ import (
 	"mtp20access/client"
 	"mtp20access/global"
 	commonRequest "mtp20access/model/common/request"
+	"mtp20access/model/common/response"
 	"mtp20access/model/quote/request"
+	"mtp20access/utils"
 	"net/http"
 
 	"github.com/gin-gonic/gin"
@@ -13,24 +15,57 @@ import (
 	"go.uber.org/zap"
 )
 
-var upGrader = websocket.Upgrader{
-	ReadBufferSize:  1000000,
-	WriteBufferSize: 1000000,
-	CheckOrigin: func(r *http.Request) bool {
-		return true
-	},
-}
-
 // QuoteConn 终端连接WebSocket
 func QuoteConn(c *gin.Context) (err error) {
 	// 获取请求账号信息
-	s, exists := c.Get("claims")
-	if !exists {
-		err = errors.New("获取请求账号信息异常")
-		global.M2A_LOG.Error(err.Error())
+	// s, exists := c.Get("claims")
+	// if !exists {
+	// 	err = errors.New("获取请求账号信息异常")
+	// 	global.M2A_LOG.Error(err.Error())
+	// 	return
+	// }
+	// claims := s.(*commonRequest.CustomClaims)
+
+	// 我们这里jwt鉴权取头部信息 x-token 登录时回返回token信息 这里前端需要把token存储到cookie或者本地localStorage中 不过需要跟后端协商过期时间 可以约定刷新令牌或者重新登录
+	token := c.Request.Header.Get("Sec-WebSocket-Protocol")
+	if token == "" {
+		response.FailWithDetailed(gin.H{"reload": true}, "未登录或非法访问", c)
+		c.Abort()
+		return
+	}
+
+	j := utils.NewJWT()
+	// parseToken 解析token包含的信息
+	claims, err := j.ParseToken(token)
+	if err != nil {
+		if err == utils.ErrTokenExpired {
+			response.FailWithCodeAndDetail(gin.H{"reload": true}, response.ERROR_TOKEN_EXPIRED, "授权已过期", c)
+			// c.Abort()
+			return
+		}
+		response.FailWithDetailed(gin.H{"reload": true}, err.Error(), c)
+		// c.Abort()
+		return
+	}
+	// 从Redis获取登录信息
+	loginMap, err := j.GetRedisLogin(claims.LoginID, claims.Group)
+	if err != nil {
+		response.FailWithCodeAndDetail(gin.H{"reload": true}, response.ERROR_TOKEN_OTHER_LOGIN, "您的帐户异地登陆或令牌失效", c)
+		// c.Abort()
+		return
+	}
+	// 判断Token是否有效
+	if redisToken, isHas := loginMap["token"]; isHas {
+		if redisToken != token {
+			response.FailWithCodeAndDetail(gin.H{"reload": true}, response.ERROR_TOKEN_OTHER_LOGIN, "您的帐户异地登陆或令牌失效", c)
+			// c.Abort()
+			return
+		}
+	} else {
+		response.FailWithDetailed(gin.H{"reload": true}, "未登录或非法访问", c)
+		// c.Abort()
 		return
 	}
-	claims := s.(*commonRequest.CustomClaims)
 
 	// 获取登录账户信息
 	client, exists := client.Clients[claims.SessionID]
@@ -40,13 +75,26 @@ func QuoteConn(c *gin.Context) (err error) {
 		return
 	}
 
+	// 需要注意的是,如果前端通过websocket连接时指定了Sec-WebSocket-Protocol,后端接收到连接后,必须原封不动的将Sec-WebSocket-Protocol头信息返回给前端,否则连接会抛出异常。
+	// c.Header("Sec-WebSocket-Protocol", token)
+	// c.String(200, "ok")
 	// 将http连接升级为websocket连接
+	upGrader := websocket.Upgrader{
+		ReadBufferSize:  1000000,
+		WriteBufferSize: 1000000,
+		CheckOrigin: func(r *http.Request) bool {
+			return true
+		},
+		//将获取的参数放进这个数组
+		Subprotocols: []string{token},
+	}
 	ws, err := upGrader.Upgrade(c.Writer, c.Request, nil)
 	if err != nil {
 		err = errors.New("连接错误")
 		global.M2A_LOG.Error("将http连接升级为websocket连接失败", zap.Any("err", err))
 		return
 	}
+
 	client.SetWebSocket(ws)
 
 	return