package service import ( "context" "errors" "regexp" "strings" "time" "github.com/gin-gonic/gin" "github.com/go-redis/redis/v8" "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/models" "github.com/mhaya/game/game_cluster/nodes/webadmin/common" "github.com/mhaya/game/game_cluster/nodes/webadmin/entity" "github.com/mhaya/game/game_cluster/nodes/webadmin/model" mhayaLogger "github.com/mhaya/logger" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" "golang.org/x/crypto/bcrypt" ) type Admin struct { db *mongo.Database } func NewAdmin() *Admin { return &Admin{ db: mdb.MDB, } } func (a *Admin) GetDB() *mongo.Database { return a.db } func (a *Admin) GetDBName() string { return "admin" } func CheckPasswordHash(password, hash string) bool { err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) return err == nil } // HashPassword 加密密码 func HashPassword(password string) (string, error) { bytes, err := bcrypt.GenerateFromPassword([]byte(password), 14) return string(bytes), err } // Login 登录 func (a *Admin) Login(ctx *gin.Context, username string, password string) (*entity.AdminResp, *code.Result) { user, err := a.QueryUserByUsername(ctx, username) if err != nil { mhayaLogger.Warnf("Login QueryUserByUsername error:", err) if errors.Is(err, mongo.ErrNoDocuments) { return nil, common.NewResult(code.AccountNotExistError) } return nil, common.NewResult(code.InternalError) } // 判断用户状态 if user.Status != 1 { return nil, common.NewResult(code.DisabledUserError) } // 判断密码 if !CheckPasswordHash(password, user.Password) { return nil, common.NewResult(code.UserNameOrPasswordError) } token, err := mdb.RDB.Get(ctx, user.Username).Result() if err != nil && err != redis.Nil { mhayaLogger.Warnf("Login Get error:", err) return nil, common.NewResult(code.InternalError) } if token == "" { // 创建token generateToken, err := user.GenerateToken() if err != nil { mhayaLogger.Warnf("Login GenerateToken error:", err) return nil, common.NewResult(code.InternalError) } // 保存token 到 redis 中 过期时间为1天 err = mdb.RDB.Set(ctx, user.Username, generateToken, 24*time.Hour).Err() if err != nil { mhayaLogger.Warnf("Login Set error:", err) return nil, common.NewResult(code.InternalError) } err = a.loginAuthSetRoleRedis(user.RoleId, generateToken) if err != nil { mhayaLogger.Warnf("Login loginAuthSetRoleRedis error:", err) return nil, common.NewResult(code.InternalError) } token = generateToken } // 更新用户登录时间 _, err = mdb.MDB.Collection(a.GetDBName()).UpdateOne(ctx, bson.M{"username": username}, bson.M{"$set": bson.M{"last_login_time": time.Now().Unix()}}) if err != nil { mhayaLogger.Warnf("Login UpdateOne last_login_time error:", err) return nil, common.NewResult(code.InternalError) } // 更新用户IP ip := ctx.ClientIP() _, err = mdb.MDB.Collection(a.GetDBName()).UpdateOne(ctx, bson.M{"username": username}, bson.M{"$set": bson.M{"last_login_ip": ip}}) if err != nil { mhayaLogger.Warnf("Login UpdateOne ip error:", err) return nil, common.NewResult(code.InternalError) } // 返回用户信息 resp := &entity.AdminResp{ ToKen: token, RoleID: user.RoleId, } return resp, nil } // LoginAuthSetRoleRedis 登录时写入该用户的权限 func (a *Admin) loginAuthSetRoleRedis(roleID, generateToken string) error { if roleID == constant.AdminAccess { mdb.RDB.HSet(context.Background(), "admin::token::"+generateToken, constant.AdminAccess, 1) mdb.RDB.Expire(context.Background(), "admin::token::"+generateToken, 24*time.Hour).Err() return nil } // 写入redis role := models.Roles{} collection := mdb.MDB.Collection(role.TableName()) roleIdObj, _ := primitive.ObjectIDFromHex(roleID) filter := bson.M{"_id": roleIdObj, "status": 1} err := collection.FindOne(context.TODO(), filter).Decode(&role) if err != nil { return err } roleAccess := models.RoleAccess{} collection = mdb.MDB.Collection(roleAccess.TableName()) roleAccessFilter := bson.M{"role_id": roleID} err = collection.FindOne(context.TODO(), roleAccessFilter).Decode(&roleAccess) if err != nil { return err } // 写入redis var accessIDS []primitive.ObjectID for _, v := range roleAccess.AccessID { accessIdObj, _ := primitive.ObjectIDFromHex(v) accessIDS = append(accessIDS, accessIdObj) } access := models.Access{} var accessList []models.Access collection = mdb.MDB.Collection(access.TableName()) accessFilter := bson.M{"_id": bson.M{"$in": accessIDS}} cursor, err := collection.Find(context.Background(), accessFilter) if err != nil { return err } if err = cursor.All(context.Background(), &accessList); err != nil { return err } for _, v := range accessList { mdb.RDB.HSet(context.Background(), "admin::token::"+generateToken, v.URL, 1) } mdb.RDB.Expire(context.Background(), "admin::token::"+generateToken, 24*time.Hour).Err() return nil } // QueryUserByUsername 根据用户名查询用户 func (a *Admin) QueryUserByUsername(ctx context.Context, username string) (*model.Admin, error) { admin := &model.Admin{} err := mdb.MDB.Collection(a.GetDBName()).FindOne(ctx, bson.M{"username": username}).Decode(&admin) if errors.Is(err, mongo.ErrNoDocuments) { if username != "admin" { return nil, err } // 如果是admin 登录的话 创建一个初始的admin并且存入数据库 pwd, err := HashPassword("123456") if err != nil { return nil, err } admin = &model.Admin{ Username: constant.AdminAccess, Password: pwd, RealName: constant.AdminAccess, Pid: "0", RoleId: constant.AdminAccess, ManagerAuth: 0, Status: 1, CreatedAt: 0, UpdatedAt: 0, DeletedAt: 0, LastLoginIp: "", LastLoginTime: 0, } _, err = mdb.MDB.Collection(a.GetDBName()).InsertOne(ctx, bson.M{ "username": constant.AdminAccess, "password": pwd, "real_name": constant.AdminAccess, "pid": "0", "role_id": constant.AdminAccess, "status": 1, }) if err != nil { return nil, err } return admin, nil } if err != nil { return nil, err } return admin, nil } // ChangePassword 修改管理员密码 func (a *Admin) ChangePassword(ctx context.Context, username string, password string) *code.Result { // 更新密码 password, _ = HashPassword(password) _, err := mdb.MDB.Collection(a.GetDBName()).UpdateOne(ctx, bson.M{"username": username}, bson.M{"$set": bson.M{"password": password}}) if err != nil { mhayaLogger.Warnf("ChangePassword UpdateOne error:", err) return common.NewResult(code.InternalError) } return nil } // Add 添加管理员 func (a *Admin) Add(ctx context.Context, username string, password string, realName string, pid string, roleId string, status int) *code.Result { // 判断账号是否重复 admin := model.Admin{} err := mdb.MDB.Collection(a.GetDBName()).FindOne(ctx, bson.M{"username": username}).Decode(&admin) if errors.Is(err, mongo.ErrNoDocuments) { password, _ = HashPassword(password) _, err := mdb.MDB.Collection(a.GetDBName()).InsertOne(ctx, bson.M{ "username": username, "password": password, "real_name": realName, "pid": pid, "role_id": roleId, "status": status, "created_at": time.Now().Unix(), "updated_at": time.Now().Unix(), }) if err != nil { mhayaLogger.Warnf("Add InsertOne error:", err) return common.NewResult(code.InternalError) } return nil } return common.NewResult(code.AccountExistError) } // Delete 删除管理员 func (a *Admin) Delete(ctx context.Context, username string) *code.Result { _, err := mdb.MDB.Collection(a.GetDBName()).DeleteOne(ctx, bson.M{"username": username}) if err != nil { mhayaLogger.Warnf("Delete DeleteOne error:", err) return common.NewResult(code.InternalError) } return nil } // UpdateStatus updateStatus func (a *Admin) UpdateStatus(ctx context.Context, username string, status int) *code.Result { _, err := mdb.MDB.Collection(a.GetDBName()).UpdateOne(ctx, bson.M{"username": username}, bson.M{"$set": bson.M{"status": status}}) if err != nil { mhayaLogger.Warnf("Delete UpdateOne error:", err) return common.NewResult(code.InternalError) } return nil } // FindAll 查找所有管理员信息 func (a *Admin) FindAll(ctx context.Context, req entity.AdminFindAllReq) (*entity.AdminListResp, *code.Result) { // 日志记录 mhayaLogger.Warnf("FindAll req: %#v", req) // 验证参数 page := req.Page if req.Page <= 0 { page = 1 } pageSize := req.Size if req.Size <= 0 { pageSize = 10 } // 构建查询条件 filter := bson.M{} if req.Username != "" { filter["username"] = bson.M{"$regex": escapeRegex(req.Username), "$options": "i"} } // 查询总数 count, err := mdb.MDB.Collection("admin").CountDocuments(ctx, filter) if err != nil { mhayaLogger.Warnf("FindAll CountDocuments error:", err) return nil, common.NewResult(code.InternalError) } // 设置分页选项 skip := (page - 1) * pageSize limit := pageSize findOptions := options.Find().SetSkip(int64(skip)).SetLimit(int64(limit)) // 执行查询 cursor, err := mdb.MDB.Collection("admin").Find(ctx, filter, findOptions) if err != nil { mhayaLogger.Warnf("FindAll Find error:", err) return nil, common.NewResult(code.InternalError) } defer func() { if closeErr := cursor.Close(ctx); closeErr != nil { mhayaLogger.Warnf("Error closing cursor: %v", closeErr) } }() // 解析结果 admins := make([]*model.Admin, 0) for cursor.Next(ctx) { var admin model.Admin err := cursor.Decode(&admin) if err != nil { mhayaLogger.Warnf("FindAll Decode error:", err) return nil, common.NewResult(code.InternalError) } admins = append(admins, &admin) } if err := cursor.Err(); err != nil { mhayaLogger.Warnf("FindAll cursor error:", err) return nil, common.NewResult(code.InternalError) } var details []*entity.AdminListDetail for _, admin := range admins { roleName := "" roleName, _ = a.GetRoleName(admin.RoleId) details = append(details, &entity.AdminListDetail{ Id: admin.GetID(), Username: admin.Username, RealName: admin.RealName, RoleId: admin.RoleId, RoleName: roleName, Status: admin.Status, CreatedAt: admin.CreatedAt, UpdatedAt: admin.UpdatedAt, LastLoginIp: admin.LastLoginIp, LastLoginTime: admin.LastLoginTime, }) } return &entity.AdminListResp{ Details: details, Total: count, }, nil } func (a *Admin) GetRoleName(roleID string) (string, error) { objID, err := primitive.ObjectIDFromHex(roleID) if err != nil { return "", err } var role models.Roles err = mdb.MDB.Collection(role.TableName()).FindOne(context.Background(), bson.M{"_id": objID}).Decode(&role) return role.Name, err } // GetServerStatus 获取服务器状态 func (a *Admin) GetServerStatus(ctx context.Context) ([]*models.PlayerServerLoadStat, *code.Result) { // 执行查询 cursor, err := mdb.MDB.Collection(constant.CNameServerLoadStat).Find(ctx, bson.M{}) if err != nil { mhayaLogger.Warnf("GetServerStatus Find error:", err) return nil, common.NewResult(code.InternalError) } defer func() { if closeErr := cursor.Close(ctx); closeErr != nil { mhayaLogger.Warnf("Error closing cursor: %v", closeErr) } }() // 解析结果 admins := make([]*models.PlayerServerLoadStat, 0) for cursor.Next(ctx) { var admin models.PlayerServerLoadStat err := cursor.Decode(&admin) if err != nil { mhayaLogger.Warnf("GetServerStatus Decode error:", err) return nil, common.NewResult(code.InternalError) } admins = append(admins, &admin) } if err := cursor.Err(); err != nil { mhayaLogger.Warnf("GetServerStatus cursor error:", err) return nil, common.NewResult(code.InternalError) } return admins, nil } // 辅助函数:对 username 进行脱敏处理 func maskUsername(username string) string { if username == "" { return "" } return strings.Repeat("*", len(username)) } // 辅助函数:对正则表达式进行转义 func escapeRegex(s string) string { return regexp.QuoteMeta(s) }