package service import ( "electricity_bill_calc/cache" "electricity_bill_calc/config" "electricity_bill_calc/exceptions" "electricity_bill_calc/logger" "electricity_bill_calc/model" "electricity_bill_calc/repository" "electricity_bill_calc/tools" "electricity_bill_calc/tools/serial" "electricity_bill_calc/types" "time" "github.com/fufuok/utils/xhash" "github.com/google/uuid" "github.com/samber/lo" "go.uber.org/zap" ) type _UserService struct { log *zap.Logger } var UserService = _UserService{ log: logger.Named("Service", "User"), } func (us _UserService) MatchUserPassword(controlCode, testCode string) bool { hashedCode := xhash.Sha512Hex(testCode) return controlCode == hashedCode } // 处理用户登录的通用过程。 func (us _UserService) processUserLogin(username, password string, userType []int16) (*model.User, *model.UserDetail, error) { us.log.Info("处理用户登录。", zap.String("username", username)) user, err := repository.UserRepository.FindUserByUsername(username) if err != nil { us.log.Error("处理用户登录失败。", zap.String("username", username), zap.Error(err)) return nil, nil, err } if user == nil { us.log.Warn("处理用户登录失败,用户不存在。", zap.String("username", username)) return nil, nil, exceptions.NewAuthenticationError(404, "用户不存在。") } if !lo.Contains(userType, user.UserType) { us.log.Warn("处理用户登录失败,用户类型错误。", zap.String("username", username), zap.Int16s("user type", userType)) return nil, nil, exceptions.NewAuthenticationError(400, "用户类型不正确。") } if !user.Enabled { us.log.Warn("处理用户登录失败,用户已被禁用。", zap.String("username", username)) return nil, nil, exceptions.NewAuthenticationError(403, "用户已被禁用。") } if user.ResetNeeded { us.log.Warn("处理用户登录失败,用户需要重置密码。", zap.String("username", username)) authErr := exceptions.NewAuthenticationError(401, "用户凭据已失效。") authErr.NeedReset = true return nil, nil, authErr } if !us.MatchUserPassword(user.Password, password) { us.log.Warn("处理用户登录失败,密码错误。", zap.String("username", username)) return nil, nil, exceptions.NewAuthenticationError(402, "用户凭据不正确。") } userDetail, err := repository.UserRepository.FindUserDetailById(user.Id) if err != nil { us.log.Error("处理企业用户登录失败,查询用户详细信息失败。", zap.String("username", username), zap.Error(err)) return nil, nil, err } if userDetail.ServiceExpiration.Before(time.Now()) { us.log.Warn("处理企业用户登录失败,用户服务已过期。", zap.String("username", username)) return nil, nil, exceptions.NewAuthenticationError(406, "用户服务期限已过。") } return user, userDetail, nil } // 处理企业用户登录 func (us _UserService) ProcessEnterpriseUserLogin(username, password string) (*model.Session, error) { user, userDetail, err := us.processUserLogin(username, password, []int16{model.USER_TYPE_ENT}) if err != nil { us.log.Error("处理企业用户登录失败。", zap.String("username", username), zap.Error(err)) return nil, err } token, _ := uuid.NewRandom() userSession := &model.Session{ Uid: user.Id, Name: user.Username, Type: user.UserType, Token: token.String(), ExpiresAt: types.Now().Add(config.ServiceSettings.MaxSessionLife), } if userDetail != nil && userDetail.Name != nil { userSession.Name = *userDetail.Name } err = cache.CacheSession(userSession) if err != nil { us.log.Error("处理企业用户登录失败,缓存用户会话失败。", zap.String("username", username), zap.Error(err)) return nil, err } return userSession, nil } // 处理运维、监管用户登录 func (us _UserService) ProcessManagementUserLogin(username, password string) (*model.Session, error) { user, userDetail, err := us.processUserLogin(username, password, []int16{model.USER_TYPE_OPS, model.USER_TYPE_SUP}) if err != nil { us.log.Error("处理运维、监管用户登录失败。", zap.String("username", username), zap.Error(err)) return nil, err } token, _ := uuid.NewRandom() userSession := &model.Session{ Uid: user.Id, Name: user.Username, Type: user.UserType, Token: token.String(), ExpiresAt: time.Now().Add(config.ServiceSettings.MaxSessionLife), } if userDetail != nil { userSession.Name = *userDetail.Name } err = cache.CacheSession(userSession) if err != nil { us.log.Error("处理运维、监管用户登录失败,缓存用户会话失败。", zap.String("username", username), zap.Error(err)) return nil, err } return userSession, nil } // 创建用户账号的通用方法。 func (us _UserService) CreateUserAccount(user *model.User, detail *model.UserDetail) (*string, error) { if lo.IsEmpty(user.Id) { var prefix string if user.UserType == model.USER_TYPE_ENT { prefix = "E" } else { prefix = "S" } serial.StringSerialRequestChan <- 1 user.Id = serial.Prefix(prefix, <-serial.StringSerialResponseChan) detail.Id = user.Id } verifyCode := tools.RandStr(10) user.Password = xhash.Sha512Hex(verifyCode) user.ResetNeeded = true res, err := repository.UserRepository.CreateUser(*user, *detail, nil) if err != nil || !res { us.log.Error("创建用户账号失败。", zap.String("username", user.Username), zap.Error(err)) return nil, err } return &verifyCode, nil }