🎨 新增ip检测配置功能

This commit is contained in:
2025-11-16 22:55:13 +08:00
parent 6e924c9630
commit 598d5e439a
8 changed files with 175 additions and 20 deletions

View File

@@ -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,6 +159,16 @@ func (*AppUserApi) WechatLogin(ctx *gin.Context) {
}
}()
// 判断是否为新用户
if isNewUser {
ipCheckStatus := false
err = global.GVA_DB.Model(&user2.IpCheck{}).Select("status").Scan(&ipCheckStatus).Error
if err != nil {
global.GVA_LOG.Error("获取IP检测状态失败", zap.Error(err))
}
if ipCheckStatus {
adcodes := utils.CheckIPInAdcodes(loginLog.Address)
if !adcodes {
global.GVA_LOG.Warn("异常登录地址", zap.String("address", loginLog.Address), zap.Uint("userId", user.ID))
@@ -170,6 +181,8 @@ func (*AppUserApi) WechatLogin(ctx *gin.Context) {
r.Banned("用户已被禁用", ctx)
return
}
}
}
// 生成token
token, claims, err := user_jwt.LoginToken(user)
@@ -195,6 +208,7 @@ func (*AppUserApi) WechatLogin(ctx *gin.Context) {
"User": user,
"Token": token,
"ExpiresAt": claims.RegisteredClaims.ExpiresAt.Unix() * 1000,
"IsNewUser": isNewUser,
}, "登录成功", ctx)
}

View File

@@ -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)
}

View File

@@ -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))

View File

@@ -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"`
}

View File

@@ -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检测状态
}
}

View File

@@ -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 {

View File

@@ -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
}

View File

@@ -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 {
// 检测是否包含