From 598d5e439ab61b2dd14b4a7cfe5312d2647d2de4 Mon Sep 17 00:00:00 2001 From: Echo <1711788888@qq.com> Date: Sun, 16 Nov 2025 22:55:13 +0800 Subject: [PATCH] =?UTF-8?q?:art:=20=E6=96=B0=E5=A2=9Eip=E6=A3=80=E6=B5=8B?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/v1/app/user.go | 34 +++++++++++++++++------- api/v1/user/user.go | 55 +++++++++++++++++++++++++++++++++++++++ initialize/gorm.go | 1 + model/app/request/user.go | 8 ++++++ router/user/user.go | 9 +++++++ service/app/user.go | 9 ++++--- service/user/user.go | 48 ++++++++++++++++++++++++++++++++++ utils/ip.go | 31 +++++++++++++++++----- 8 files changed, 175 insertions(+), 20 deletions(-) diff --git a/api/v1/app/user.go b/api/v1/app/user.go index 1964827..3db3580 100644 --- a/api/v1/app/user.go +++ b/api/v1/app/user.go @@ -55,7 +55,7 @@ func (*AppUserApi) Login(ctx *gin.Context) { return } - user, err := appUserService.Login(p) + user, isNewUser, err := appUserService.Login(p) if err != nil { r.FailWithMessage("登录失败", ctx) return @@ -104,6 +104,7 @@ func (*AppUserApi) Login(ctx *gin.Context) { "User": user, "Token": token, "ExpiresAt": claims.RegisteredClaims.ExpiresAt.Unix() * 1000, + "IsNewUser": isNewUser, }, "登录成功", ctx) } else if err != nil { global.GVA_LOG.Error("设置登录状态失败!", zap.Error(err)) @@ -127,7 +128,7 @@ func (*AppUserApi) WechatLogin(ctx *gin.Context) { return } - user, err := appUserService.WechatLogin(info) + user, isNewUser, err := appUserService.WechatLogin(info) if err != nil { r.FailWithMessage("登录失败:"+err.Error(), ctx) return @@ -158,17 +159,29 @@ func (*AppUserApi) WechatLogin(ctx *gin.Context) { } }() - adcodes := utils.CheckIPInAdcodes(loginLog.Address) - if !adcodes { - global.GVA_LOG.Warn("异常登录地址", zap.String("address", loginLog.Address), zap.Uint("userId", user.ID)) + // 判断是否为新用户 + if isNewUser { + ipCheckStatus := false - user.Status = 0 - if err := global.GVA_DB.Save(&user).Error; err != nil { - global.GVA_LOG.Error("禁用用户失败!", zap.Error(err)) + err = global.GVA_DB.Model(&user2.IpCheck{}).Select("status").Scan(&ipCheckStatus).Error + if err != nil { + global.GVA_LOG.Error("获取IP检测状态失败", zap.Error(err)) } - r.Banned("用户已被禁用", ctx) - return + if ipCheckStatus { + adcodes := utils.CheckIPInAdcodes(loginLog.Address) + if !adcodes { + global.GVA_LOG.Warn("异常登录地址", zap.String("address", loginLog.Address), zap.Uint("userId", user.ID)) + + user.Status = 0 + if err := global.GVA_DB.Save(&user).Error; err != nil { + global.GVA_LOG.Error("禁用用户失败!", zap.Error(err)) + } + + r.Banned("用户已被禁用", ctx) + return + } + } } // 生成token @@ -195,6 +208,7 @@ func (*AppUserApi) WechatLogin(ctx *gin.Context) { "User": user, "Token": token, "ExpiresAt": claims.RegisteredClaims.ExpiresAt.Unix() * 1000, + "IsNewUser": isNewUser, }, "登录成功", ctx) } diff --git a/api/v1/user/user.go b/api/v1/user/user.go index e09487c..3a31c9b 100644 --- a/api/v1/user/user.go +++ b/api/v1/user/user.go @@ -5,6 +5,7 @@ import ( "git.echol.cn/loser/lckt/model/app" common "git.echol.cn/loser/lckt/model/common/request" r "git.echol.cn/loser/lckt/model/common/response" + "git.echol.cn/loser/lckt/model/user" "git.echol.cn/loser/lckt/model/user/request" "github.com/gin-gonic/gin" "go.uber.org/zap" @@ -272,3 +273,57 @@ func (a *UserApi) SetTeacherExpectRate(context *gin.Context) { r.OkWithMessage("修改讲师信息成功", context) } + +// ===========================IP检测配置========================== + +// SetIpCheckConfig 设置IP检测配置 +func (a *UserApi) SetIpCheckConfig(ctx *gin.Context) { + var p user.IpCheck + if err := ctx.ShouldBind(&p); err != nil { + r.FailWithMessage(err.Error(), ctx) + global.GVA_LOG.Error("参数错误,设置IP检测配置失败", zap.Error(err)) + return + } + config, err := userService.SetIpConfig(p) + if err != nil { + r.FailWithMessage("设置IP检测配置失败", ctx) + return + } + r.OkWithData(config, ctx) +} + +// GetIpCheckConfig 获取IP检测配置 +func (a *UserApi) GetIpCheckConfig(ctx *gin.Context) { + config, err := userService.GetIpConfig() + if err != nil { + r.FailWithMessage("获取IP检测配置失败", ctx) + return + } + r.OkWithData(config, ctx) +} + +// GetIpCheckStatus 获取IP检测状态 +func (a *UserApi) GetIpCheckStatus(ctx *gin.Context) { + status, err := userService.GetIpStatus() + if err != nil { + r.FailWithMessage("获取IP检测状态失败", ctx) + return + } + r.OkWithDetailed(status, "获取IP检测状态成功", ctx) +} + +// SetIpCheckStatus 设置IP检测状态 +func (a *UserApi) SetIpCheckStatus(ctx *gin.Context) { + var p user.IpCheck + if err := ctx.ShouldBind(&p); err != nil { + r.FailWithMessage(err.Error(), ctx) + global.GVA_LOG.Error("参数错误,设置IP检测状态失败", zap.Error(err)) + return + } + status, err := userService.SetIpStatus(p.Status) + if err != nil { + r.FailWithMessage("设置IP检测状态失败", ctx) + return + } + r.OkWithDetailed(status, "设置IP检测状态成功", ctx) +} diff --git a/initialize/gorm.go b/initialize/gorm.go index fc24800..25a8ebb 100644 --- a/initialize/gorm.go +++ b/initialize/gorm.go @@ -89,6 +89,7 @@ func RegisterTables() { app.BalanceLog{}, app.With{}, app.Domain{}, + user.IpCheck{}, ) if err != nil { global.GVA_LOG.Error("register table failed", zap.Error(err)) diff --git a/model/app/request/user.go b/model/app/request/user.go index 311897c..dd02c3e 100644 --- a/model/app/request/user.go +++ b/model/app/request/user.go @@ -11,3 +11,11 @@ type UpdateTeacherVipPriceBatch struct { Ids []uint `json:"ids" form:"ids" vd:"@:len($)>0; msg:'请选择要修改的讲师VIP'"` Price float64 `json:"price" form:"price" vd:"@:len($)>0; msg:'请输入讲师VIP价格'"` // 讲师VIP价格 } + +type IpCheckConfigReq struct { + IpAddrs []string `json:"ip_addrs" form:"ip_addrs" vd:"@:len($)>0; msg:'请输入要检测的IP地址列表'"` // IP地址列表 +} + +type IpCheckStatus struct { + Status bool `json:"status" form:"status"` +} diff --git a/router/user/user.go b/router/user/user.go index 4521294..087b4b8 100644 --- a/router/user/user.go +++ b/router/user/user.go @@ -10,6 +10,7 @@ type UserRouter struct{} // InitUserRouter 初始化 用户相关 路由信息 func (s *UserRouter) InitUserRouter(Router *gin.RouterGroup, PublicRouter *gin.RouterGroup) { userRouter := Router.Group("app_user").Use(middleware.OperationRecord()) + publicRouter := PublicRouter.Group("app_user") { userRouter.GET("list", userApi.GetUserList) // 获取用户列表 userRouter.PUT("setBalance", userApi.SetBalance) // 更新用户余额 @@ -34,4 +35,12 @@ func (s *UserRouter) InitUserRouter(Router *gin.RouterGroup, PublicRouter *gin.R userRouter.DELETE("teacher_vip", teacherVipApi.DeleteTeacherVip) // 删除讲师VIP userRouter.PUT("/teacher_vip/price", teacherVipApi.UpdatePriceBatch) // 批量设置讲师课程价格 } + + { + userRouter.PUT("ipStatus", userApi.SetIpCheckStatus) // 设置ip检测状态 + userRouter.PUT("ipCon", userApi.SetIpCheckConfig) // 设置ip检测配置 + publicRouter.GET("ipCon", userApi.GetIpCheckConfig) // 获取ip检测配置 + userRouter.GET("ipStatus", userApi.GetIpCheckStatus) // 获取ip检测状态 + } + } diff --git a/service/app/user.go b/service/app/user.go index 8bef9de..c1dc34e 100644 --- a/service/app/user.go +++ b/service/app/user.go @@ -19,7 +19,8 @@ import ( type AppUserService struct{} // Login 用户登录 -func (u *AppUserService) Login(req request.CodeLoginReq) (users user.User, err error) { +func (u *AppUserService) Login(req request.CodeLoginReq) (users user.User, isNewUser bool, err error) { + isNewUser = false // 1. 判断用户是否存在 var count int64 err = global.GVA_DB.Model(&user.User{}).Where("phone = ?", req.Phone).Count(&count).Error @@ -30,6 +31,7 @@ func (u *AppUserService) Login(req request.CodeLoginReq) (users user.User, err e // 2. 如果用户不存在,则创建用户 if count == 0 { + isNewUser = true user := user.User{ Phone: req.Phone, UserLabel: 1, @@ -51,7 +53,8 @@ func (u *AppUserService) Login(req request.CodeLoginReq) (users user.User, err e } // WechatLogin 微信登录 -func (u *AppUserService) WechatLogin(info *providers.User) (users user.User, err error) { +func (u *AppUserService) WechatLogin(info *providers.User) (users user.User, isNewUser bool, err error) { + isNewUser = false openID := info.GetOpenID() var count int64 if openID == "" { @@ -76,7 +79,7 @@ func (u *AppUserService) WechatLogin(info *providers.User) (users user.User, err global.GVA_LOG.Error("创建用户失败", zap.Error(err)) return } - return newUser, nil + return newUser, true, nil } else { err = global.GVA_DB.Where("open_id = ?", openID).First(&users).Error if err != nil { diff --git a/service/user/user.go b/service/user/user.go index 43b1a86..ddd7436 100644 --- a/service/user/user.go +++ b/service/user/user.go @@ -392,3 +392,51 @@ func (u *UserService) SetTeacherExpectRate(p request.SetTeacherInfo) (err error) } return } + +func (u *UserService) SetIpConfig(p user.IpCheck) (user.IpCheck, error) { + p.ID = 1 + err := global.GVA_DB.Save(&p).Error + if err != nil { + global.GVA_LOG.Error("修改IP检测配置失败", zap.Error(err)) + return p, err + } + return p, nil +} + +func (u *UserService) GetIpConfig() (ipConfig user.IpCheck, err error) { + ipConfig.ID = 1 + err = global.GVA_DB.First(&ipConfig).Error + if err != nil { + global.GVA_LOG.Error("获取IP检测配置失败", zap.Error(err)) + return + } + return +} + +func (u *UserService) SetIpStatus(status bool) (bool, error) { + var ipConfig user.IpCheck + ipConfig.ID = 1 + err := global.GVA_DB.First(&ipConfig).Error + if err != nil { + global.GVA_LOG.Error("获取IP检测配置失败", zap.Error(err)) + return false, err + } + ipConfig.Status = status + err = global.GVA_DB.Save(&ipConfig).Error + if err != nil { + global.GVA_LOG.Error("修改IP检测状态失败", zap.Error(err)) + return false, err + } + return status, nil +} + +func (u *UserService) GetIpStatus() (status bool, err error) { + var ipConfig user.IpCheck + err = global.GVA_DB.Where("id = 1").First(&ipConfig).Error + if err != nil { + global.GVA_LOG.Error("获取IP检测配置失败", zap.Error(err)) + return + } + status = ipConfig.Status + return +} diff --git a/utils/ip.go b/utils/ip.go index 4a7638a..9710ae1 100644 --- a/utils/ip.go +++ b/utils/ip.go @@ -3,6 +3,9 @@ package utils import ( "encoding/json" "fmt" + "git.echol.cn/loser/lckt/global" + user2 "git.echol.cn/loser/lckt/model/user" + "go.uber.org/zap" "net/http" "strings" "time" @@ -14,13 +17,6 @@ type ipAdcodeResp struct { } `json:"adcode"` } -// adcodes 是允许的地区编码列表 -var adcodes = []string{ - "重庆", - "海南", - "广东", -} - func GetIPAdcode(ip string) string { url := fmt.Sprintf("https://api.vore.top/api/IPdata?ip=%s", ip) client := &http.Client{Timeout: 5 * time.Second} @@ -38,6 +34,27 @@ func GetIPAdcode(ip string) string { // CheckIPInAdcodes 检测用户IP是否在指定的地区编码范围内 func CheckIPInAdcodes(ipAdcode string) bool { + // 查询IP配置 + ipCon := user2.IpCheck{} + err := global.GVA_DB.First(&ipCon).Error + if err != nil { + global.GVA_LOG.Error("获取IP配置失败", zap.Error(err)) + return false + } + // 如果IP检测未启用,直接返回true + if !ipCon.Status { + return true + } + // 解析允许的地区编码列表 + var adcodes []string + // 通过逗号分隔 + for _, code := range strings.Split(ipCon.Addrs, ",") { + trimmed := strings.TrimSpace(code) + if trimmed != "" { + adcodes = append(adcodes, trimmed) + } + } + lower := strings.ToLower(ipAdcode) for _, code := range adcodes { // 检测是否包含