From a5add3dd73e6efdc62c8484926922961c34af63b Mon Sep 17 00:00:00 2001 From: kevin Date: Wed, 12 Nov 2025 20:04:38 +0800 Subject: [PATCH] up --- backend/defConfig/configTemp.yaml | 6 +- backend/defConfig/errorCodes.json | 4 +- backend/models/configs.go | 7 +- backend/models/def.go | 14 ++- backend/models/log.go | 53 +++++++++-- backend/models/sql.go | 44 +++++---- backend/routers/apiUsers.go | 94 +++++++++++++++++-- .../ops_vue_js/src/components/HeardMain.vue | 76 ++++++++------- frontent/ops_vue_js/src/i18n/en.json | 5 +- frontent/ops_vue_js/src/i18n/zh-CN.json | 5 +- frontent/ops_vue_js/src/my_network_func.js | 4 +- frontent/ops_vue_js/src/myfunc.js | 29 +++++- frontent/ops_vue_js/src/stores/user.js | 4 + frontent/ops_vue_js/src/views/loginView.vue | 72 +++++++++++++- .../ops_vue_js/src/views/registerView.vue | 2 +- 15 files changed, 328 insertions(+), 91 deletions(-) diff --git a/backend/defConfig/configTemp.yaml b/backend/defConfig/configTemp.yaml index eaf86ad..a366bef 100644 --- a/backend/defConfig/configTemp.yaml +++ b/backend/defConfig/configTemp.yaml @@ -18,10 +18,8 @@ database: user: cookieTimeout: 604800 - passHashType: "md5" #密码哈希类型 text md5 - avatarSavePath: "/data/avatar/" #头像保存的真实位置 - avatarGinrouterPath: "/avatar/" #gin 路由的路径 - avatarPath: "/static/avatars/def.png" + passHashType: "md5" #密码哈希类型 text md5 md5salt + file: maxSize: 52428800 diff --git a/backend/defConfig/errorCodes.json b/backend/defConfig/errorCodes.json index 8aa501e..55c10db 100644 --- a/backend/defConfig/errorCodes.json +++ b/backend/defConfig/errorCodes.json @@ -3,6 +3,8 @@ "apiErr":-1, "postErr":-2, "jsonErr":-3, - "userNameDup":-4 + "userNameDup":-4, + "userNameNoFund":-41, + "userPassIncorrect":-42 } \ No newline at end of file diff --git a/backend/models/configs.go b/backend/models/configs.go index 6a865c6..d80bb5e 100644 --- a/backend/models/configs.go +++ b/backend/models/configs.go @@ -15,11 +15,8 @@ type ConfigsWeb_ struct { } type ConfigsUser_ struct { - CookieTimeout int `mapstructure:"cookieTimeout"` - PassHashType string `mapstructure:"passHashType"` - AvatarSavePath string `mapstructure:"avatarSavePath"` - AvatarGinrouterPath string `mapstructure:"avatarGinrouterPath"` - AvatarPath string `mapstructure:"avatarPath"` + CookieTimeout int `mapstructure:"cookieTimeout"` + PassHashType string `mapstructure:"passHashType"` } type ConfigsFile_ struct { diff --git a/backend/models/def.go b/backend/models/def.go index 15db41e..9e22137 100644 --- a/backend/models/def.go +++ b/backend/models/def.go @@ -39,13 +39,19 @@ func Md5Str(str string) string { return hashString2 } -func HashUserPass(str string) string { +func HashUserPass(user *TabUser_) { switch ConfigsUser.PassHashType { case "text": - return str + break case "md5": - return Md5Str(str) + user.Pass = Md5Str(user.Pass) + + case "md5salt": + if user.Salt == "" { + user.Salt = RandStr32() + } + user.Pass = Md5Str(Md5Str(user.Pass) + user.Salt) + } - return GetCurrentTimeString() + RandStr32() //如果转换失败返回当前时间,避免撞库 } diff --git a/backend/models/log.go b/backend/models/log.go index 8a07644..7c6242e 100644 --- a/backend/models/log.go +++ b/backend/models/log.go @@ -1,17 +1,50 @@ package models -import "time" +import ( + "net" + "strings" -type APIRequestLog struct { - ID int64 `gorm:"primaryKey;column:id" json:"id"` - IPAddress string `gorm:"column:ip_address;size:45;not null" json:"ip_address"` - Path string `gorm:"column:path;size:500;not null" json:"path"` - Method string `gorm:"column:method;size:10;not null" json:"method"` - StatusCode int `gorm:"column:status_code;index" json:"status_code"` - Message string `gorm:"column:error_message;type:text" json:"error_message"` - CreatedAt time.Time `gorm:"column:created_at;default:CURRENT_TIMESTAMP" json:"created_at"` + "github.com/gin-gonic/gin" +) + +// GetRealIP 获取真实IP(处理代理) +func GetRealIP(c *gin.Context) string { + // 优先级顺序 + headers := []string{ + "CF-Connecting-IP", // Cloudflare + "True-Client-IP", + "X-Forwarded-For", + "X-Real-IP", + } + + for _, header := range headers { + if ip := c.GetHeader(header); ip != "" { + // 处理多个IP的情况(如 X-Forwarded-For: client, proxy1, proxy2) + if strings.Contains(ip, ",") { + ips := strings.Split(ip, ",") + ip = strings.TrimSpace(ips[0]) + } + + if net.ParseIP(ip) != nil { + return ip + } + } + } + + // 最后使用Gin的ClientIP方法 + return c.ClientIP() } -func LogAdd() { +func LogAdd(c *gin.Context, msg string) { + + var logtemp APIRequestLog_ + + logtemp.IPAddress = GetRealIP(c) + logtemp.Path = c.Request.URL.Path + logtemp.Method = c.Request.Method + logtemp.Message = msg + + //fmt.Println(logtemp) + DB.Create(&logtemp) } diff --git a/backend/models/sql.go b/backend/models/sql.go index cd90a90..06a29cc 100644 --- a/backend/models/sql.go +++ b/backend/models/sql.go @@ -25,11 +25,12 @@ type TabFileInfo_ struct { } type TabUser_ struct { - ID uint `gorm:"primaryKey;autoIncrement"` // 自增主键 - Name string `gorm:"size:100;uniqueIndex"` // 唯一约束索引 - Email string `gorm:"size:255;index"` // 字符串长度限制100 索引 - Pass string `gorm:"size:128"` // 建议存储哈希后的密码 - Type string `gorm:"size:64;default:user"` // + ID uint `gorm:"primaryKey;autoIncrement"` // 自增主键 + Name string `gorm:"size:100;uniqueIndex"` // 唯一约束索引 + Email string `gorm:"size:255;index"` // 字符串长度限制100 索引 + Pass string `gorm:"size:128"` // 建议存储哈希后的密码 + Type string `gorm:"size:64;default:user"` // + Salt string `gorm:"size:64;"` Date time.Time `gorm:"type:datetime;default:CURRENT_TIMESTAMP"` // 默认当前时间 } @@ -67,19 +68,24 @@ type TabUserInfo_ struct { // } type TabCookie_ struct { - ID uint `gorm:"primaryKey;autoIncrement"` - UserID uint `gorm:"size:16;not null"` - Name string `gorm:"size:255;not null;index"` - Value string `gorm:"size:255;not null;index"` - Domain string `gorm:"size:255;not null"` - Path string `gorm:"size:255;not null;default:/"` - ExpiresAt time.Time `gorm:"type:datetime;index"` - CreatedAt time.Time `gorm:"type:datetime;not null;default:CURRENT_TIMESTAMP"` - UpdatedAt time.Time `gorm:"type:datetime;index;not null;default:CURRENT_TIMESTAMP"` - SecureFlag bool `gorm:"not null;default:false"` - HttpOnly bool `gorm:"not null;default:false"` - SameSite string `gorm:"size:10;not null;default:'Lax'"` - PartitionKey string `gorm:"size:50"` + ID uint `gorm:"primaryKey;autoIncrement"` + UserID uint `gorm:"size:16;not null"` + Name string `gorm:"size:255;not null;index"` + Value string `gorm:"size:255;not null;index"` + ExpiresAt time.Time `gorm:"type:datetime;index"` + CreatedAt time.Time `gorm:"type:datetime;not null;default:CURRENT_TIMESTAMP"` + UpdatedAt time.Time `gorm:"type:datetime;index;not null;default:CURRENT_TIMESTAMP"` + Remember bool `gorm:"default:false"` +} + +type APIRequestLog_ struct { + ID int64 `gorm:"primaryKey;column:id" json:"id"` + IPAddress string `gorm:"column:ip_address;size:45;not null" json:"ip_address"` + Path string `gorm:"column:path;size:500;not null" json:"path"` + Method string `gorm:"column:method;size:10;not null" json:"method"` + StatusCode int `gorm:"column:status_code;index" json:"status_code"` + Message string `gorm:"column:error_message;type:text" json:"error_message"` + CreatedAt time.Time `gorm:"column:created_at;type:datetime;default:CURRENT_TIMESTAMP" json:"created_at"` } func DatabaseInit() error { @@ -115,5 +121,7 @@ func DatabaseInit() error { DB.AutoMigrate(&TabFileInfo_{}) + DB.AutoMigrate(&APIRequestLog_{}) + return nil } diff --git a/backend/routers/apiUsers.go b/backend/routers/apiUsers.go index 06ac0d7..325d6bf 100644 --- a/backend/routers/apiUsers.go +++ b/backend/routers/apiUsers.go @@ -3,6 +3,7 @@ package routers import ( "fmt" "ops/models" + "strconv" "time" "github.com/gin-gonic/gin" @@ -20,8 +21,12 @@ func ApiInit() { if models.DB.Where(&user).First(&user).Error == nil { } else { - fmt.Println("用户不存在") - user.Pass = models.HashUserPass("adminpassword") + //fmt.Println("用户不存在") + + //对密码加盐 + user.Salt = models.RandStr32() + user.Pass = "adminpassword" + models.HashUserPass(&user) models.DB.Create(&user) // 传入指针 } @@ -54,6 +59,12 @@ type From_user_add struct { Userpass string `json:"userpass"` } +type From_user_login struct { + Username string `json:"username"` + Userpass string `json:"userpass"` + Remember bool `json:"remember"` +} + func ApiUser(r *gin.RouterGroup) { r.GET("/test", func(ctx *gin.Context) { @@ -62,6 +73,67 @@ func ApiUser(r *gin.RouterGroup) { r.POST("/test", func(ctx *gin.Context) { ReturnJson(ctx, "apiOK", nil) }) + //用户登陆 + r.POST("/login", func(ctx *gin.Context) { + var loginuser From_user_login + data, _ := SeparateData(ctx) + if data != nil { + if err := mapstructure.Decode(data, &loginuser); err == nil { + if loginuser.Username != "" && loginuser.Userpass != "" { + //传入的数据都ok,获取用户信息 + + getuser := models.TabUser_{ + Name: loginuser.Username, + } + + if models.DB.Where(&getuser).First(&getuser).Error == nil { + //倒入数据 + user := models.TabUser_{ + Pass: loginuser.Userpass, //密码明文 + Salt: getuser.Salt, //保存的盐制 + } + //哈希密 + models.HashUserPass(&user) + if user.Pass == getuser.Pass { + //用户密码正确,生成cookie + cookie := models.TabCookie_{ + UserID: getuser.ID, + Name: "login", + Value: models.RandStr32(), + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + ExpiresAt: time.Now().Add(time.Duration(models.ConfigsUser.CookieTimeout) * time.Second), //计算过期时间, + Remember: loginuser.Remember, + } + models.DB.Create(&cookie) // 传入指针 + + redata := map[string]interface{}{ + "cookie": cookie, + } + + ReturnJson(ctx, "apiOK", redata) + } else { + ReturnJson(ctx, "userPassIncorrect", nil) + } + + } else { + //用户不存在 + ReturnJson(ctx, "userNameNoFund", nil) + } + + } else { + ReturnJson(ctx, "jsonErr", nil) + } + } else { + ReturnJson(ctx, "jsonErr", nil) + } + + } else { + ReturnJson(ctx, "postErr", nil) + } + }) + + //用户注册 r.POST("/register", func(ctx *gin.Context) { //转换传进来的数据 var jsonData From_user_add @@ -79,8 +151,7 @@ func ApiUser(r *gin.RouterGroup) { // Date 字段无需赋值,数据库会自动填充默认值 } if newUser.Name != "" && newUser.Pass != "" && newUser.Email != "" { - //对用户的密码进行哈希替换 - newUser.Pass = models.HashUserPass(newUser.Pass) + //用户名是唯一的,先读取是否有这个用户名 var user models.TabUser_ user.Name = newUser.Name @@ -90,13 +161,18 @@ func ApiUser(r *gin.RouterGroup) { ReturnJson(ctx, "userNameDup", nil) } else { //fmt.Println("用户不存在") + + //对密码加盐 + newUser.Salt = models.RandStr32() + + //对用户的密码进行哈希替换 + models.HashUserPass(&newUser) + models.DB.Create(&newUser) // 传入指针 - // //创建info - // var user_info models.TabUserInfo_ - // user_info.AvatarPath = models.ConfigsUser.AvatarPath - // user_info.UserID = newUser.ID - // models.DB.Create(&user_info) // 传入指针 + //创建用户后写一个log + + models.LogAdd(ctx, "New user id:"+strconv.Itoa(int(newUser.ID))) ReturnJson(ctx, "apiOK", nil) } diff --git a/frontent/ops_vue_js/src/components/HeardMain.vue b/frontent/ops_vue_js/src/components/HeardMain.vue index ce998f0..f23bd39 100644 --- a/frontent/ops_vue_js/src/components/HeardMain.vue +++ b/frontent/ops_vue_js/src/components/HeardMain.vue @@ -1,46 +1,45 @@