package router import ( "bytes" "context" "errors" "io" "net/http" "time" "github.com/gin-gonic/gin" "github.com/go-redis/redis/v8" jsoniter "github.com/json-iterator/go" mhayaTime "github.com/mhaya/extend/time" cfacade "github.com/mhaya/facade" "github.com/mhaya/game/game_cluster/internal/code" "github.com/mhaya/game/game_cluster/internal/constant" "github.com/mhaya/game/game_cluster/internal/mdb" "github.com/mhaya/game/game_cluster/internal/mdb/eventmodels" "github.com/mhaya/game/game_cluster/internal/mdb/models" "github.com/mhaya/game/game_cluster/internal/param" rpcLogstash "github.com/mhaya/game/game_cluster/internal/rpc/logstash" "github.com/mhaya/game/game_cluster/nodes/webadmin/common" "github.com/mhaya/game/game_cluster/nodes/webadmin/entity" mhayaLogger "github.com/mhaya/logger" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" ) var ( json = jsoniter.ConfigCompatibleWithStandardLibrary ) func Auth(app cfacade.IApplication) gin.HandlerFunc { return func(c *gin.Context) { // 请求开始时间 startTime := mhayaTime.Now().UnixMilli() tokenString := "" roleId := "" var err error defer func() { sendLogRecord(c, app, tokenString, roleId, startTime) }() tokenString = c.GetHeader("Token") if tokenString == "" { common.PackUnauthorizedResult(c, code.UnauthorizedError, "token is empty") return } roleId, err = mdb.RDB.Get(context.Background(), tokenString).Result() if err != nil && err != redis.Nil { mhayaLogger.Warnf("Auth Get error: %s", err.Error()) common.PackUnauthorizedResult(c, code.InternalError, "token is empty") return } if roleId == "" { common.PackUnauthorizedResult(c, code.UnauthorizedError, "token is invalid") return } if roleId != constant.AdminAccess { urlAccess, err := mdb.RDB.HGet(context.Background(), common.GetTokenKey(tokenString), c.Request.URL.Path).Result() if err != nil { mhayaLogger.Warnf("Auth HGet s error: %s", err.Error()) common.PackUnauthorizedResult(c, code.InternalError, "") return } // 检查url权限 if urlAccess == "" { common.PackUnauthorizedResult(c, code.UnauthorizedError, "token is no auth") return } // 非管理员需要进行ip校验 openIpWhitelist := app.Settings().Get("open_ip_whitelist").ToBool() if openIpWhitelist { err = checkIPWhitelist(c) if err != nil { mhayaLogger.Warnf("Auth checkIPWhitelist error: %s", err.Error()) common.PackForbiddenResult(c, code.ForbiddenError, "ip is no auth") return } } } adminAccess, err := mdb.RDB.HGet(context.Background(), common.GetTokenKey(tokenString), constant.AdminAccess).Result() if err != nil { mhayaLogger.Warnf("Auth HGet ss error: %s", err.Error()) common.PackUnauthorizedResult(c, code.InternalError, "") return } // 检查管理员权限 if adminAccess == "" { common.PackUnauthorizedResult(c, code.UnauthorizedError, "token is no auth") return } c.Next() } } // checkIP func checkIPWhitelist(c *gin.Context) error { // 获取请求的ip ip := c.ClientIP() var whitelistModel *models.Whitelist collection := mdb.MDB.Collection(whitelistModel.TableName()) // 设置超时时间 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() // 确保在函数退出时取消上下文 // 示例:查询 IP 是否在白名单中 err := collection.FindOne(ctx, bson.M{"ip": ip}).Decode(&whitelistModel) if err != nil && err != mongo.ErrNoDocuments { return err } // 根据查询结果决定是否允许访问 if whitelistModel == nil { return errors.New("IP not in whitelist") // 拒绝访问 } return nil // 允许访问 } func sendLogRecord(c *gin.Context, app cfacade.IApplication, tokenString, roleId string, startTime int64) { userName, _ := mdb.RDB.Get(context.Background(), common.GetUserNameKey(tokenString)).Result() nodeId := app.NodeId() req, err := packBackendOperationEventReq(nodeId, &eventmodels.BackendOperationEventContent{ UserBasic: eventmodels.UserBasic{ UserName: userName, IsRobot: false, }, EventBasic: eventmodels.EventBasic{ ServerId: nodeId, IsSuccess: func() bool { return c.Writer.Status() == http.StatusOK }(), CreateAt: mhayaTime.Now().Unix(), }, RoleId: roleId, Path: c.Request.URL.Path, Method: c.Request.Method, StatusCode: c.Writer.Status(), Dur: mhayaTime.Now().UnixMilli() - startTime, ClientIP: c.ClientIP(), ErrorMessage: c.Errors.ByType(gin.ErrorTypePrivate).String(), }) if err != nil { mhayaLogger.Warnf("sendLogRecord packBackendOperationEventReq error: %s, token: %s", err.Error(), tokenString) return } rpcLogstash.HandleLogRecord(app, req) } func packBackendOperationEventReq(nodeId string, content *eventmodels.BackendOperationEventContent) (*param.HandleLogReq, error) { bytes, err := json.Marshal(content) if err != nil { return nil, err } return ¶m.HandleLogReq{ ServerId: nodeId, EventName: content.EventName(), JsonContent: string(bytes), }, nil } func loginRecordMiddleware(app cfacade.IApplication) gin.HandlerFunc { return func(c *gin.Context) { // 请求开始时间 startTime := mhayaTime.Now().UnixMilli() body, err := io.ReadAll(c.Request.Body) if err != nil { mhayaLogger.Warnf("loginRecordMiddleware ReadAll Request.Body error: %s", err.Error()) return } // 关闭body defer c.Request.Body.Close() var reqBody entity.AdminLoginReq err = json.Unmarshal(body, &reqBody) if err != nil { mhayaLogger.Warnf("loginRecordMiddleware Unmarshal Request.Body error: %s", err.Error()) return } // 写回请求体,以便其他中间件或路由可以正常读取 c.Request.Body = io.NopCloser(bytes.NewBuffer(body)) c.Next() nodeId := app.NodeId() req, err := packBackendOperationEventReq(nodeId, &eventmodels.BackendOperationEventContent{ UserBasic: eventmodels.UserBasic{ UserName: reqBody.Username, IsRobot: false, }, EventBasic: eventmodels.EventBasic{ ServerId: nodeId, IsSuccess: func() bool { return c.Writer.Status() == http.StatusOK }(), CreateAt: mhayaTime.Now().Unix(), }, Path: c.Request.URL.Path, Method: c.Request.Method, StatusCode: c.Writer.Status(), Dur: mhayaTime.Now().UnixMilli() - startTime, ClientIP: c.ClientIP(), ErrorMessage: c.Errors.ByType(gin.ErrorTypePrivate).String(), }) if err != nil { mhayaLogger.Warnf("loginRecordMiddleware packBackendOperationEventReq error: %s", err.Error()) return } rpcLogstash.HandleLogRecord(app, req) } }