428 lines
12 KiB
Go
428 lines
12 KiB
Go
package service
|
|
|
|
import (
|
|
"ego/internal/model"
|
|
"ego/internal/serializer"
|
|
"ego/internal/types"
|
|
"ego/internal/util"
|
|
"ego/pkg/logger"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"go.uber.org/zap"
|
|
"golang.org/x/crypto/bcrypt"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
const (
|
|
// PassWordCost 密码加密难度
|
|
PassWordCost = 12
|
|
// Suspend 被封禁用户
|
|
Suspend = "-1"
|
|
// Active 未激活用户
|
|
Active = "1"
|
|
// Inactive 激活用户
|
|
Inactive = "0"
|
|
)
|
|
|
|
// SysUserService 管理用户登录的服务
|
|
type SysUserService struct {
|
|
Db *gorm.DB
|
|
}
|
|
|
|
// NewSysUserService 构建用户登录服务
|
|
func NewSysUserService(db *gorm.DB) *SysUserService {
|
|
return &SysUserService{
|
|
Db: db,
|
|
}
|
|
}
|
|
|
|
type UserLoginRequest struct {
|
|
Account string `form:"account" json:"account" binding:"required,min=5,max=30"`
|
|
PassWord string `form:"password" json:"password" binding:"required,min=8,max=40"`
|
|
Checked *bool `form:"checked" json:"checked" binding:"required"`
|
|
Phone string `form:"phone" json:"phone"`
|
|
VerifyCode string `form:"verifyCode" json:"verifyCode"`
|
|
}
|
|
|
|
// UserRegisterRequest 用户注册表单验证
|
|
type UserRegisterRequest struct {
|
|
NickName string `form:"nickName" json:"nickName" binding:"required,min=2,max=30"`
|
|
UserName string `form:"userName" json:"userName" binding:"required,min=5,max=30"`
|
|
PassWord string `form:"passWord" json:"passWord" binding:"required,min=8,max=40"`
|
|
PasswordConfirm string `form:"passWordConfirm" json:"passWordConfirm" binding:"required,min=8,max=40"`
|
|
}
|
|
|
|
// Login 用户登录函数
|
|
func (s *SysUserService) Login(c *gin.Context) serializer.Response {
|
|
var user model.SysUser
|
|
u := UserLoginRequest{}
|
|
if err := c.ShouldBind(&u); err != nil {
|
|
logger.Error(c, "参数绑定错误!", zap.Error(err))
|
|
c.Set("msg", "参数绑定错误!")
|
|
return serializer.Err(serializer.CodeParamErr, "参数绑定错误!", err)
|
|
}
|
|
c.Set("account", u.Account)
|
|
if err := s.Db.Where("user_name = ?", u.Account).First(&user).Error; err != nil {
|
|
logger.Error(c, "账号或密码错误!")
|
|
c.Set("msg", "账号或密码错误!")
|
|
return serializer.ParamErr("账号或密码错误!", nil)
|
|
}
|
|
if user.Status == Suspend {
|
|
logger.Error(c, "账号已封禁!")
|
|
c.Set("msg", "账号已封禁!")
|
|
return serializer.ParamErr("账号已封禁!", nil)
|
|
}
|
|
if user.Status == Inactive {
|
|
logger.Error(c, "账号未激活!")
|
|
c.Set("msg", "账号未激活!")
|
|
return serializer.ParamErr("账号未激活!", nil)
|
|
}
|
|
if !CheckPassWord(u.PassWord, user.PassWord) {
|
|
logger.Error(c, "账号或密码错误!")
|
|
c.Set("msg", "账号或密码错误!")
|
|
return serializer.ParamErr("账号或密码错误!", nil)
|
|
}
|
|
if token, err := util.GenerateToken(user.UserId, user.UserName); err == nil {
|
|
logger.Info(c, "用户登录", zap.String("redisKey", util.TokenGroup+user.UserName))
|
|
// 删除key
|
|
del := util.Del(c, util.TokenGroup+user.UserName)
|
|
if del != nil {
|
|
logger.Error(c, "redis 删除失败!", zap.Error(del))
|
|
c.Set("msg", "redis 删除失败!")
|
|
return serializer.ParamErr("系统繁忙稍后重试!", nil)
|
|
}
|
|
// 结果放入redis
|
|
set := util.Set(c, util.TokenGroup+user.UserName, token, time.Hour*24)
|
|
if set != nil {
|
|
logger.Error(c, "redis 放入失败!", zap.Error(set))
|
|
c.Set("msg", "redis 放入失败!")
|
|
return serializer.ParamErr("系统繁忙稍后重试!", nil)
|
|
}
|
|
c.Set("status", Active)
|
|
return types.BuildUserResponseHasToken(user, token)
|
|
}
|
|
return serializer.ParamErr("系统繁忙稍后重试!", nil)
|
|
}
|
|
|
|
// UserLogout 退出登录
|
|
func (s *SysUserService) UserLogout(c *gin.Context) serializer.Response {
|
|
// 退出登录
|
|
go func() {
|
|
tokenString := c.GetHeader("Authorization")
|
|
token, err := util.ParseToken(tokenString[8:])
|
|
if err == nil {
|
|
username := token["username"].(string)
|
|
// 删除key
|
|
if err := util.Del(c, util.TokenGroup+username); err != nil {
|
|
logger.Error(c, "退出登录失败!", zap.Error(err))
|
|
} else {
|
|
logger.Info(c, "用户退出登录成功!", zap.String("redisKey", util.TokenGroup+username))
|
|
}
|
|
}
|
|
}()
|
|
return serializer.Succ("退出登录成功!", true)
|
|
}
|
|
|
|
// GetUser 用ID获取用户
|
|
func GetUser(id string, d *gorm.DB) (model.SysUser, error) {
|
|
var user model.SysUser
|
|
result := d.Where("user_id = ?", id).First(&user)
|
|
if result.Error == nil {
|
|
user.PassWord = "" // 清除密码
|
|
}
|
|
return user, result.Error
|
|
}
|
|
|
|
// SetPassWord 设置密码
|
|
func SetPassWord(passWord string, sysUser *model.SysUser) error {
|
|
bytes, err := bcrypt.GenerateFromPassword([]byte(passWord), PassWordCost)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
sysUser.PassWord = string(bytes)
|
|
return nil
|
|
}
|
|
|
|
// CheckPassWord 校验密码
|
|
func CheckPassWord(password string, passwordDigest string) bool {
|
|
err := bcrypt.CompareHashAndPassword([]byte(passwordDigest), []byte(password))
|
|
return err == nil
|
|
}
|
|
|
|
// valid 验证表单
|
|
func (s *SysUserService) valid(u *UserRegisterRequest) *serializer.Response {
|
|
if u.PasswordConfirm != u.PassWord {
|
|
return &serializer.Response{
|
|
Code: 40001,
|
|
Msg: "两次输入的密码不相同",
|
|
}
|
|
}
|
|
|
|
count := int64(0)
|
|
s.Db.Model(&model.SysUser{}).Where("nick_name = ?", u.NickName).Count(&count)
|
|
if count > 0 {
|
|
return &serializer.Response{
|
|
Code: 40001,
|
|
Msg: "昵称被占用",
|
|
}
|
|
}
|
|
|
|
count = 0
|
|
s.Db.Model(&model.SysUser{}).Where("user_name = ?", u.UserName).Count(&count)
|
|
if count > 0 {
|
|
return &serializer.Response{
|
|
Code: 40001,
|
|
Msg: "用户名已经注册",
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Register 用户注册
|
|
func (s *SysUserService) Register(c *gin.Context) serializer.Response {
|
|
u := UserRegisterRequest{}
|
|
if err := c.ShouldBind(&u); err != nil {
|
|
return serializer.Err(serializer.CodeParamErr, "参数绑定错误!", err)
|
|
}
|
|
now := time.Now()
|
|
user := model.SysUser{
|
|
NickName: u.NickName,
|
|
UserName: u.UserName,
|
|
Status: Active,
|
|
CreateTime: &now,
|
|
}
|
|
// 生成ID
|
|
if id, err := SysSequenceServiceBuilder(user.TableName()).GenerateId(); err == nil {
|
|
user.UserId = id
|
|
} else {
|
|
return serializer.DBErr("序列生成失败!", err)
|
|
}
|
|
// 表单验证
|
|
if err := s.valid(&u); err != nil {
|
|
logger.Error(c, err.Msg, zap.String("NickName", u.NickName), zap.String("UserName", u.UserName))
|
|
return *err
|
|
}
|
|
// 密码加密
|
|
if err := SetPassWord(u.PassWord, &user); err != nil {
|
|
logger.Error(c, "密码加密失败!")
|
|
return serializer.Err(serializer.CodeEncryptError, "密码加密失败!", err)
|
|
}
|
|
// 使用事务封装数据库操作
|
|
err := s.Db.Transaction(func(tx *gorm.DB) error {
|
|
if err := tx.Create(&user).Error; err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
logger.Error(c, "注册失败!")
|
|
return serializer.ParamErr("注册失败", err)
|
|
}
|
|
return types.BuildUserResponse(user)
|
|
}
|
|
|
|
// Create 创建用户
|
|
func (s *SysUserService) Create(c *gin.Context) serializer.Response {
|
|
var user model.SysUser
|
|
if err := c.ShouldBind(&user); err != nil {
|
|
logger.Error(c, "参数绑定失败!")
|
|
return serializer.ParamErr("参数绑定失败!", err)
|
|
}
|
|
|
|
if user.Status == "" {
|
|
user.Status = Active
|
|
}
|
|
|
|
now := time.Now()
|
|
user.CreateTime = &now
|
|
|
|
createBy := c.GetString("id")
|
|
user.CreateBy = createBy
|
|
|
|
id, err := SysSequenceServiceBuilder(user.TableName()).GenerateId()
|
|
if err != nil {
|
|
return serializer.DBErr("创建用户失败!", err)
|
|
}
|
|
user.UserId = id
|
|
|
|
if err := s.Db.Create(&user).Error; err != nil {
|
|
logger.Error(c, "创建用户失败!")
|
|
return serializer.DBErr("创建用户失败!", err)
|
|
}
|
|
return serializer.Succ("创建用户成功!", user)
|
|
}
|
|
|
|
// DeleteByID 根据ID删除用户
|
|
func (s *SysUserService) DeleteByID(c *gin.Context) serializer.Response {
|
|
id := c.Param("id")
|
|
if id == "" {
|
|
logger.Error(c, "id 不可为空!")
|
|
}
|
|
|
|
// 删除逻辑
|
|
data := map[string]any{
|
|
"del_flag": "1",
|
|
"update_time": time.Now(),
|
|
"update_by": c.GetString("id"),
|
|
}
|
|
|
|
var user model.SysUser
|
|
if err := s.Db.Model(&user).Where("user_id = ?", id).Updates(data).Error; err != nil {
|
|
logger.Error(c, "未查询用户信息!")
|
|
return serializer.DBErr("删除用户失败!", err)
|
|
}
|
|
|
|
return serializer.Succ("删除用户成功!", user)
|
|
}
|
|
|
|
// UpdateByID 根据ID更新用户
|
|
func (s *SysUserService) UpdateByID(c *gin.Context) serializer.Response {
|
|
var user model.SysUser
|
|
if err := c.ShouldBind(&user); err != nil {
|
|
logger.Error(c, "参数绑定失败!")
|
|
return serializer.ParamErr("参数绑定失败!", err)
|
|
}
|
|
|
|
id := user.UserId
|
|
if id == "" {
|
|
logger.Error(c, "id 不可为空!")
|
|
return serializer.ParamErr("id不可为空!", fmt.Errorf("id不可为空"))
|
|
}
|
|
|
|
if err := s.Db.Model(&user).Where("user_id = ?", id).Updates(&user).Error; err != nil {
|
|
logger.Error(c, "更新用户信息失败!")
|
|
return serializer.DBErr("更新用户信息失败!", err)
|
|
}
|
|
return serializer.Succ("更新用户信息成功!", user)
|
|
}
|
|
|
|
// GetByID 根据ID获取用户
|
|
func (s *SysUserService) GetByID(c *gin.Context) serializer.Response {
|
|
var user model.SysUser
|
|
if err := s.Db.Where("user_id = ?", c.Param("id")).First(&user).Error; err != nil {
|
|
logger.Error(c, "获取用户信息失败!")
|
|
return serializer.DBErr("获取用户信息失败!", err)
|
|
}
|
|
user.PassWord = "" // 清除密码
|
|
return serializer.Succ("查询成功!", user)
|
|
}
|
|
|
|
// DeleteByIDs 批量删除用户
|
|
func (s *SysUserService) DeleteByIDs(c *gin.Context) serializer.Response {
|
|
var ids types.Payload
|
|
if err := c.ShouldBind(&ids); err != nil {
|
|
return serializer.ParamErr("参数绑定失败!", err)
|
|
}
|
|
|
|
// 删除逻辑
|
|
data := map[string]any{
|
|
"del_flag": "1",
|
|
"update_time": time.Now(),
|
|
"update_by": c.GetString("id"),
|
|
}
|
|
|
|
if err := s.Db.Model(&model.SysUser{}).Where("user_id in (?)", ids.Ids).Updates(data).Error; err != nil {
|
|
logger.Error(c, "批量删除用户失败!")
|
|
return serializer.DBErr("批量删除用户失败!", err)
|
|
}
|
|
return serializer.Succ("批量删除用户成功!", nil)
|
|
}
|
|
|
|
// GetByCondition 条件查询用户
|
|
func (s *SysUserService) GetByCondition(c *gin.Context) serializer.Response {
|
|
var p types.Params
|
|
if err := c.ShouldBind(&p); err != nil {
|
|
return serializer.ParamErr("参数绑定失败!", err)
|
|
}
|
|
|
|
queryStr, args, err := p.ConvertToGormConditions()
|
|
if err != nil {
|
|
logger.Error(c, "参数绑定失败!")
|
|
return serializer.ParamErr("参数绑定失败!", err)
|
|
}
|
|
|
|
var total int64
|
|
var users []model.SysUser
|
|
offset := (p.Page - 1) * p.Limit
|
|
|
|
// 构建基础查询
|
|
db := s.Db.Model(&model.SysUser{})
|
|
|
|
// 如果有查询条件,添加条件
|
|
if queryStr != "" {
|
|
db = db.Where(queryStr, args...)
|
|
}
|
|
|
|
// 排序
|
|
if p.Sort != "" {
|
|
db = db.Order(p.Sort)
|
|
}
|
|
|
|
// 执行分页查询
|
|
if err := db.Where("del_flag = ?", "0").Offset(offset).Limit(p.Limit).Find(&users).Error; err != nil {
|
|
logger.Error(c, "获取用户信息失败!")
|
|
return serializer.DBErr("获取用户信息失败!", err)
|
|
}
|
|
|
|
// 清除所有用户的密码
|
|
for i := range users {
|
|
users[i].PassWord = ""
|
|
}
|
|
|
|
// 执行总数查询
|
|
if err := db.Where("del_flag = ?", "0").Count(&total).Error; err != nil {
|
|
logger.Error(c, "获取用户总数失败!")
|
|
return serializer.DBErr("获取用户总数失败!", err)
|
|
}
|
|
|
|
return serializer.Succ("查询成功!", gin.H{
|
|
"total": total,
|
|
"items": users,
|
|
"page": p.Page,
|
|
"limit": p.Limit,
|
|
})
|
|
}
|
|
|
|
// ListByIDs 根据ID列表获取用户
|
|
func (s *SysUserService) ListByIDs(c *gin.Context) serializer.Response {
|
|
var ids types.Payload
|
|
if err := c.ShouldBind(&ids); err != nil {
|
|
return serializer.ParamErr("参数绑定失败!", err)
|
|
}
|
|
|
|
var users []model.SysUser
|
|
if err := s.Db.Where("user_id in (?)", ids.Ids).Find(&users).Error; err != nil {
|
|
logger.Error(c, "获取用户信息失败!")
|
|
return serializer.DBErr("获取用户信息失败!", err)
|
|
}
|
|
|
|
// 清除所有用户的密码
|
|
for i := range users {
|
|
users[i].PassWord = ""
|
|
}
|
|
|
|
return serializer.Succ("查询成功!", users)
|
|
}
|
|
|
|
// CurrentUser 获取当前用户
|
|
func (s *SysUserService) CurrentUser(c *gin.Context) (*model.SysUser, error) {
|
|
tokenString := c.GetHeader("Authorization")
|
|
var user model.SysUser
|
|
token, err := util.ParseToken(tokenString[8:])
|
|
if err != nil {
|
|
return nil, fmt.Errorf("获取当前用户失败! %v", err)
|
|
}
|
|
|
|
id := token["id"].(string)
|
|
if err := s.Db.Model(&user).Where("user_id = ?", id).First(&user).Error; err != nil {
|
|
logger.Error(c, "获取当前用户失败!", zap.Error(err))
|
|
return nil, err
|
|
}
|
|
// 清除密码
|
|
user.PassWord = ""
|
|
return &user, nil
|
|
}
|