From 46b66cda5b8aec2bcb42198c60b613a52b6fd15b Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Mon, 31 Mar 2025 18:31:25 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AF=86=E7=A0=81=E4=B8=8D=E5=85=81?= =?UTF-8?q?=E8=AE=B8=E4=BD=BF=E7=94=A8=E6=9C=80=E8=BF=91=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E7=9A=84=E5=AF=86=E7=A0=81=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/system/controller/sys_profile.go | 14 ++++ .../system/model/sys_log_user_password.go | 16 ++++ .../repository/sys_log_user_password.go | 79 +++++++++++++++++++ .../system/service/sys_log_user_password.go | 26 ++++++ src/modules/system/service/sys_user.go | 78 +++++++++++++----- 5 files changed, 194 insertions(+), 19 deletions(-) create mode 100644 src/modules/system/model/sys_log_user_password.go create mode 100644 src/modules/system/repository/sys_log_user_password.go create mode 100644 src/modules/system/service/sys_log_user_password.go diff --git a/src/modules/system/controller/sys_profile.go b/src/modules/system/controller/sys_profile.go index ce4a44bc..e6b1e2f3 100644 --- a/src/modules/system/controller/sys_profile.go +++ b/src/modules/system/controller/sys_profile.go @@ -237,6 +237,13 @@ func (s *SysProfileController) PasswordUpdate(c *gin.Context) { return } + // 检查密码是否与历史密码一致 + err = s.sysUserService.ValidatePasswordNotAllowedHistory(userInfo.UserId, body.NewPassword) + if err != nil { + c.JSON(200, resp.ErrMsg(i18n.TKey(language, err.Error()))) + return + } + // 修改新密码 userInfo.Password = body.NewPassword userInfo.UpdateBy = userInfo.UserName @@ -296,6 +303,13 @@ func (s *SysProfileController) PasswordForce(c *gin.Context) { return } + // 检查密码是否与历史密码一致 + err = s.sysUserService.ValidatePasswordNotAllowedHistory(userInfo.UserId, body.Password) + if err != nil { + c.JSON(200, resp.ErrMsg(i18n.TKey(language, err.Error()))) + return + } + userInfo.Password = body.Password userInfo.UpdateBy = reqctx.LoginUserToUserName(c) rows := s.sysUserService.Update(userInfo) diff --git a/src/modules/system/model/sys_log_user_password.go b/src/modules/system/model/sys_log_user_password.go new file mode 100644 index 00000000..a61b209d --- /dev/null +++ b/src/modules/system/model/sys_log_user_password.go @@ -0,0 +1,16 @@ +package model + +// SysLogUserPassword 系统_用户密码变更日志表 +type SysLogUserPassword struct { + ID int64 `json:"id" gorm:"column:id;primaryKey;autoIncrement"` // ID + UserId int64 `json:"userId" gorm:"column:user_id"` // 用户ID + UserName string `json:"userName" gorm:"column:user_name"` // 用户账号 + Password string `json:"password" gorm:"column:password"` // 密码 + CreateBy string `json:"createBy" gorm:"column:create_by"` // 创建者 + CreateTime int64 `json:"createTime" gorm:"column:create_time"` // 创建时间 +} + +// TableName 表名称 +func (*SysLogUserPassword) TableName() string { + return "sys_log_user_password" +} diff --git a/src/modules/system/repository/sys_log_user_password.go b/src/modules/system/repository/sys_log_user_password.go new file mode 100644 index 00000000..9a82d822 --- /dev/null +++ b/src/modules/system/repository/sys_log_user_password.go @@ -0,0 +1,79 @@ +package repository + +import ( + "time" + + "be.ems/src/framework/database/db" + "be.ems/src/framework/logger" + "be.ems/src/modules/system/model" +) + +// NewSysLogUserPassword 实例化数据层 +var NewSysLogUserPassword = &SysLogUserPassword{} + +// SysLogUserPasswordRepository 系统_用户密码变更日志表 数据层处理 +type SysLogUserPassword struct{} + +// SelectByUserId 通过用户ID日志 pageNum为0返回日志列表 +func (r SysLogUserPassword) SelectByUserId(userId int64, pageNum int) []model.SysLogUserPassword { + rows := []model.SysLogUserPassword{} + if userId <= 0 { + return rows + } + tx := db.DB("").Model(&model.SysLogUserPassword{}) + // 构建查询条件 + tx = tx.Where("user_id = ?", userId) + // 查询数据分页 + if pageNum > 0 { + tx = tx.Limit(pageNum) + } + err := tx.Order("create_time desc").Find(&rows).Error + if err != nil { + logger.Errorf("query find err => %v", err.Error()) + return rows + } + return rows +} + +// SelectCountByUserId 通过用户ID日志数量 +func (r SysLogUserPassword) SelectCountByUserId(userId int64) int64 { + var total int64 = 0 + if userId <= 0 { + return total + } + tx := db.DB("").Model(&model.SysLogUserPassword{}) + // 构建查询条件 + tx = tx.Where("user_id = ?", userId) + // 查询数量为0直接返回 + if err := tx.Count(&total).Error; err != nil || total <= 0 { + return total + } + return total +} + +// Insert 新增信息 返回新增的数据ID +func (r SysLogUserPassword) Insert(param model.SysLogUserPassword) int64 { + if param.CreateBy != "" { + param.CreateTime = time.Now().UnixMilli() + } + // 执行插入 + if err := db.DB("").Create(¶m).Error; err != nil { + logger.Errorf("insert err => %v", err.Error()) + return 0 + } + return param.ID +} + +// DeleteByUserId 删除用户日志信息 返回受影响行数 +func (r SysLogUserPassword) DeleteByUserId(userIds []int64) int64 { + if len(userIds) <= 0 { + return 0 + } + tx := db.DB("").Where("user_id in ?", userIds) + // 执行删除 + if err := tx.Delete(&model.SysLogUserPassword{}).Error; err != nil { + logger.Errorf("delete err => %v", err.Error()) + return 0 + } + return tx.RowsAffected +} diff --git a/src/modules/system/service/sys_log_user_password.go b/src/modules/system/service/sys_log_user_password.go new file mode 100644 index 00000000..c73ad917 --- /dev/null +++ b/src/modules/system/service/sys_log_user_password.go @@ -0,0 +1,26 @@ +package service + +import ( + "be.ems/src/modules/system/model" + "be.ems/src/modules/system/repository" +) + +// NewSysLogUserPassword 实例化服务层 +var NewSysLogUserPassword = &SysLogUserPassword{ + sysLogUserPasswordRepository: repository.NewSysLogUserPassword, +} + +// SysLogUserPassword 用户密码变更日志 服务层处理 +type SysLogUserPassword struct { + sysLogUserPasswordRepository *repository.SysLogUserPassword // 用户密码变更日志表日志信息 +} + +// Insert 新增信息 +func (s SysLogUserPassword) Insert(param model.SysLogUserPassword) int64 { + return s.sysLogUserPasswordRepository.Insert(param) +} + +// Delete 删除信息 +func (s SysLogUserPassword) DeleteByUserId(userIds []int64) int64 { + return s.sysLogUserPasswordRepository.DeleteByUserId(userIds) +} diff --git a/src/modules/system/service/sys_user.go b/src/modules/system/service/sys_user.go index 0f923133..93c87ee2 100644 --- a/src/modules/system/service/sys_user.go +++ b/src/modules/system/service/sys_user.go @@ -8,32 +8,36 @@ import ( "be.ems/src/framework/constants" "be.ems/src/framework/i18n" + "be.ems/src/framework/utils/crypto" + "be.ems/src/framework/utils/parse" "be.ems/src/modules/system/model" "be.ems/src/modules/system/repository" ) // NewSysUser 实例化服务层 var NewSysUser = &SysUser{ - sysUserRepository: repository.NewSysUser, - sysRoleRepository: repository.NewSysRole, - sysDeptRepository: repository.NewSysDept, - sysUserRoleRepository: repository.NewSysUserRole, - sysUserPostRepository: repository.NewSysUserPost, - sysDictTypeService: NewSysDictType, - sysDictDataService: NewSysDictData, - sysConfigService: NewSysConfig, + sysUserRepository: repository.NewSysUser, + sysRoleRepository: repository.NewSysRole, + sysDeptRepository: repository.NewSysDept, + sysUserRoleRepository: repository.NewSysUserRole, + sysUserPostRepository: repository.NewSysUserPost, + sysDictTypeService: NewSysDictType, + sysDictDataService: NewSysDictData, + sysConfigService: NewSysConfig, + sysLogUserPasswordService: NewSysLogUserPassword, } // SysUser 用户 服务层处理 type SysUser struct { - sysUserRepository *repository.SysUser // 用户服务 - sysRoleRepository *repository.SysRole // 角色服务 - sysDeptRepository *repository.SysDept // 部门服务 - sysUserRoleRepository *repository.SysUserRole // 用户与角色服务 - sysUserPostRepository *repository.SysUserPost // 用户与岗位服务 - sysDictTypeService *SysDictType // 字典类型服务 - sysDictDataService *SysDictData // 字典数据服务 - sysConfigService *SysConfig // 参数配置服务 + sysUserRepository *repository.SysUser // 用户服务 + sysRoleRepository *repository.SysRole // 角色服务 + sysDeptRepository *repository.SysDept // 部门服务 + sysUserRoleRepository *repository.SysUserRole // 用户与角色服务 + sysUserPostRepository *repository.SysUserPost // 用户与岗位服务 + sysDictTypeService *SysDictType // 字典类型服务 + sysDictDataService *SysDictData // 字典数据服务 + sysConfigService *SysConfig // 参数配置服务 + sysLogUserPasswordService *SysLogUserPassword // 用户密码变更日志服务 } // FindByPage 分页查询列表数据 @@ -140,7 +144,17 @@ func (s SysUser) insertUserPost(userId int64, postIds []int64) int64 { // Update 修改信息 func (s SysUser) Update(sysUser model.SysUser) int64 { - return s.sysUserRepository.Update(sysUser) + rows := s.sysUserRepository.Update(sysUser) + // 记录密码变更日志 + if rows > 0 && sysUser.Password != "" { + s.sysLogUserPasswordService.Insert(model.SysLogUserPassword{ + UserId: sysUser.UserId, + UserName: sysUser.UserName, + Password: crypto.BcryptHash(sysUser.Password), + CreateBy: sysUser.UpdateBy, + }) + } + return rows } // UpdateUserAndRolePost 修改用户信息同时更新角色和岗位 @@ -164,8 +178,9 @@ func (s SysUser) DeleteByIds(userIds []int64) (int64, error) { return 0, fmt.Errorf("没有权限访问用户数据!") } if len(users) == len(userIds) { - s.sysUserRoleRepository.DeleteByUserIds(userIds) // 删除用户与角色关联 - s.sysUserPostRepository.DeleteByUserIds(userIds) // 删除用户与岗位关联 + s.sysUserRoleRepository.DeleteByUserIds(userIds) // 删除用户与角色关联 + s.sysUserPostRepository.DeleteByUserIds(userIds) // 删除用户与岗位关联 + s.sysLogUserPasswordService.DeleteByUserId(userIds) // 删除用户密码变更日志 return s.sysUserRepository.DeleteByIds(userIds), nil } return 0, fmt.Errorf("删除用户信息失败!") @@ -320,3 +335,28 @@ func (s SysUser) ValidatePasswordExpireTime(passwordUpdateTime int64) (bool, err } return alertFlag, nil } + +// ValidatePasswordNotAllowedHistory 密码不允许使用最近修改的 +func (s SysUser) ValidatePasswordNotAllowedHistory(userId int64, password string) error { + passwdNotAllowedHistoryStr := s.sysConfigService.FindValueByKey("sys.user.passwdNotAllowedHistory") + if passwdNotAllowedHistoryStr == "" { + return nil + } + passwdNotAllowedHistory := parse.Number(passwdNotAllowedHistoryStr) + if passwdNotAllowedHistory <= 0 { + return nil + } + // 查询密码历史记录 + rows := s.sysLogUserPasswordService.sysLogUserPasswordRepository.SelectByUserId(userId, int(passwdNotAllowedHistory)) + if len(rows) <= 0 { + return nil + } + // 检查密码是否在历史记录中 + for _, v := range rows { + compare := crypto.BcryptCompare(password, v.Password) + if compare { + return fmt.Errorf("login.errPasswdHistory") + } + } + return nil +}