153 lines
5.4 KiB
Go
153 lines
5.4 KiB
Go
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() //生成uuid作为会话的token使用
|
|
|
|
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
|
|
}
|