perf: 通用模块分出认证模块

This commit is contained in:
TsMask
2025-03-19 11:32:57 +08:00
parent add8b9d581
commit 5040a5ae40
14 changed files with 120 additions and 113 deletions

View File

@@ -0,0 +1,174 @@
package service
import (
"fmt"
"time"
"be.ems/src/framework/config"
"be.ems/src/framework/constants"
"be.ems/src/framework/database/redis"
"be.ems/src/framework/token"
"be.ems/src/framework/utils/crypto"
"be.ems/src/framework/utils/parse"
systemModelVO "be.ems/src/modules/system/model/vo"
systemService "be.ems/src/modules/system/service"
)
// 实例化服务层 Account 结构体
var NewAccount = &Account{
sysUserService: systemService.NewSysUser,
sysConfigService: systemService.NewSysConfig,
sysRoleService: systemService.NewSysRole,
sysMenuService: systemService.NewSysMenu,
}
// 账号身份操作服务 服务层处理
type Account struct {
sysUserService *systemService.SysUser // 用户信息服务
sysConfigService *systemService.SysConfig // 参数配置服务
sysRoleService *systemService.SysRole // 角色服务
sysMenuService *systemService.SysMenu // 菜单服务
}
// ValidateCaptcha 校验验证码
func (s *Account) ValidateCaptcha(code, uuid string) error {
// 验证码检查,从数据库配置获取验证码开关 true开启false关闭
captchaEnabledStr := s.sysConfigService.FindValueByKey("sys.account.captchaEnabled")
if !parse.Boolean(captchaEnabledStr) {
return nil
}
if code == "" || uuid == "" {
// 验证码信息错误
return fmt.Errorf("captcha.err")
}
verifyKey := constants.CACHE_CAPTCHA_CODE + ":" + uuid
captcha, _ := redis.Get("", verifyKey)
if captcha == "" {
// 验证码已失效
return fmt.Errorf("captcha.errValid")
}
_ = redis.Del("", verifyKey)
if captcha != code {
// 验证码错误
return fmt.Errorf("captcha.err")
}
return nil
}
// ByUsername 登录创建用户信息
func (s Account) ByUsername(username, password string) (token.TokenInfo, error) {
tokenInfo := token.TokenInfo{}
// 检查密码重试次数
retryKey, retryCount, lockTime, err := s.passwordRetryCount(username)
if err != nil {
return tokenInfo, err
}
// 查询用户登录账号
sysUser := s.sysUserService.FindByUserName(username)
if sysUser.UserName != username {
return tokenInfo, fmt.Errorf("login.errNameOrPasswd")
}
if sysUser.DelFlag == constants.STATUS_YES {
return tokenInfo, fmt.Errorf("login.errDelFlag")
}
if sysUser.StatusFlag == constants.STATUS_NO {
return tokenInfo, fmt.Errorf("login.errStatus")
}
// 检验用户密码
compareBool := crypto.BcryptCompare(password, sysUser.Password)
if compareBool {
s.CleanLoginRecordCache(sysUser.UserName) // 清除错误记录次数
} else {
_ = redis.SetByExpire("", retryKey, retryCount+1, lockTime)
return tokenInfo, fmt.Errorf("login.errNameOrPasswd")
}
// 登录用户信息
tokenInfo.UserId = sysUser.UserId
tokenInfo.DeptId = sysUser.DeptId
tokenInfo.User = sysUser
// 用户权限组标识
if config.IsSystemUser(sysUser.UserId) {
tokenInfo.Permissions = []string{constants.SYS_PERMISSION_SYSTEM}
} else {
perms := s.sysMenuService.FindPermsByUserId(sysUser.UserId)
tokenInfo.Permissions = parse.RemoveDuplicates(perms)
}
return tokenInfo, nil
}
// UpdateLoginDateAndIP 更新登录时间和IP
func (s Account) UpdateLoginDateAndIP(tokenInfo token.TokenInfo) bool {
user := s.sysUserService.FindById(tokenInfo.UserId)
user.Password = "" // 密码不更新
user.LoginIp = tokenInfo.LoginIp
user.LoginTime = tokenInfo.LoginTime
return s.sysUserService.Update(user) > 0
}
// CleanLoginRecordCache 清除错误记录次数
func (s Account) CleanLoginRecordCache(userName string) bool {
cacheKey := fmt.Sprintf("%s:%s", constants.CACHE_PWD_ERR_COUNT, userName)
hasKey, err := redis.Has("", cacheKey)
if hasKey > 0 && err == nil {
return redis.Del("", cacheKey) == nil
}
return false
}
// passwordRetryCount 密码重试次数
func (s Account) passwordRetryCount(userName string) (string, int64, time.Duration, error) {
// 从数据库配置获取登录次数和错误锁定时间
maxRetryCountStr := s.sysConfigService.FindValueByKey("sys.user.maxRetryCount")
lockTimeStr := s.sysConfigService.FindValueByKey("sys.user.lockTime")
// 验证登录次数和错误锁定时间
maxRetryCount := parse.Number(maxRetryCountStr)
lockTime := parse.Number(lockTimeStr)
// 验证缓存记录次数
retryKey := fmt.Sprintf("%s:%s", constants.CACHE_PWD_ERR_COUNT, userName)
retryCount, err := redis.Get("", retryKey)
if retryCount == "" || err != nil {
retryCount = "0"
}
// 是否超过错误值
retryCountInt64 := parse.Number(retryCount)
if retryCountInt64 >= int64(maxRetryCount) {
// msg := fmt.Sprintf("密码输入错误 %d 次,帐户锁定 %d 分钟", maxRetryCount, lockTime)
msg := fmt.Errorf("login.errRetryPasswd") // 密码输入错误多次,帐户已被锁定
return retryKey, retryCountInt64, time.Duration(lockTime) * time.Minute, fmt.Errorf("%s", msg)
}
return retryKey, retryCountInt64, time.Duration(lockTime) * time.Minute, nil
}
// RoleAndMenuPerms 角色和菜单数据权限
func (s Account) RoleAndMenuPerms(userId int64, isSystemUser bool) ([]string, []string) {
if isSystemUser {
return []string{constants.SYS_ROLE_SYSTEM_KEY}, []string{constants.SYS_PERMISSION_SYSTEM}
}
// 角色key
var roleGroup []string
roles := s.sysRoleService.FindByUserId(userId)
for _, role := range roles {
roleGroup = append(roleGroup, role.RoleKey)
}
// 菜单权限key
perms := s.sysMenuService.FindPermsByUserId(userId)
return parse.RemoveDuplicates(roleGroup), parse.RemoveDuplicates(perms)
}
// RouteMenus 前端路由所需要的菜单
func (s Account) RouteMenus(userId int64, isSystemUser bool) []systemModelVO.Router {
var buildMenus []systemModelVO.Router
if isSystemUser {
menus := s.sysMenuService.BuildTreeMenusByUserId(0)
buildMenus = s.sysMenuService.BuildRouteMenus(menus, "")
} else {
menus := s.sysMenuService.BuildTreeMenusByUserId(userId)
buildMenus = s.sysMenuService.BuildRouteMenus(menus, "")
}
return buildMenus
}