feat: 更新多个模块以支持新的数据结构和日志格式

This commit is contained in:
TsMask
2025-02-20 10:08:27 +08:00
parent 045a2b6b01
commit f3c33b31ac
272 changed files with 13246 additions and 15885 deletions

View File

@@ -13,18 +13,17 @@ func Setup(router *gin.Engine) {
logger.Infof("开始加载 ====> common 模块路由")
// 路由主页
indexGroup := router.Group("/")
indexGroup.GET("",
// middleware.RateLimit(middleware.LimitOption{
// Time: 300,
// Count: 10,
// Type: middleware.LIMIT_IP,
// }),
router.GET("/",
middleware.RateLimit(middleware.LimitOption{
Time: 300,
Count: 10,
Type: middleware.LIMIT_IP,
}),
controller.NewIndex.Handler,
)
// 系统可暴露的配置信息
indexGroup.GET("/sys-conf", controller.NewCommont.SysConfig)
router.GET("/sys-conf", controller.NewCommon.SysConfig)
// 系统引导初始化
guideGroup := router.Group("/bootloader")
{
@@ -34,47 +33,47 @@ func Setup(router *gin.Engine) {
guideGroup.PUT("/account", middleware.PreAuthorize(nil), controller.NewBootloader.Account)
}
// 验证码操作处理
indexGroup.GET("/captchaImage",
// middleware.RateLimit(middleware.LimitOption{
// Time: 300,
// Count: 60,
// Type: middleware.LIMIT_IP,
// }),
// 验证码操作
router.GET("/captcha-image",
middleware.RateLimit(middleware.LimitOption{
Time: 300,
Count: 60,
Type: middleware.LIMIT_IP,
}),
controller.NewCaptcha.Image,
)
// 账号身份操作处理
{
indexGroup.POST("/login",
// middleware.RateLimit(middleware.LimitOption{
// Time: 300,
// Count: 10,
// Type: middleware.LIMIT_IP,
// }),
router.POST("/login",
middleware.RateLimit(middleware.LimitOption{
Time: 180,
Count: 15,
Type: middleware.LIMIT_IP,
}),
middleware.CryptoApi(true, true),
controller.NewAccount.Login,
)
indexGroup.GET("/getInfo", middleware.PreAuthorize(nil), controller.NewAccount.Info)
indexGroup.GET("/getRouters", middleware.PreAuthorize(nil), controller.NewAccount.Router)
indexGroup.POST("/logout",
router.GET("/me", middleware.PreAuthorize(nil), controller.NewAccount.Me)
router.GET("/router", middleware.PreAuthorize(nil), controller.NewAccount.Router)
router.POST("/logout",
middleware.RateLimit(middleware.LimitOption{
Time: 300,
Count: 5,
Time: 120,
Count: 15,
Type: middleware.LIMIT_IP,
}),
controller.NewAccount.Logout,
)
}
// 账号注册操作处理
// 账号注册操作
{
indexGroup.POST("/register",
// middleware.RateLimit(middleware.LimitOption{
// Time: 300,
// Count: 10,
// Type: middleware.LIMIT_IP,
// }),
router.POST("/register",
middleware.RateLimit(middleware.LimitOption{
Time: 300,
Count: 10,
Type: middleware.LIMIT_IP,
}),
middleware.CryptoApi(true, true),
controller.NewRegister.Register,
)
@@ -83,8 +82,8 @@ func Setup(router *gin.Engine) {
// 通用请求
commonGroup := router.Group("/common")
{
commonGroup.POST("/hash", middleware.PreAuthorize(nil), controller.NewCommont.Hash)
commonGroup.GET("/i18n", controller.NewCommont.I18n)
commonGroup.POST("/hash", middleware.PreAuthorize(nil), controller.NewCommon.Hash)
commonGroup.GET("/i18n", controller.NewCommon.I18n)
}
// 文件操作处理
@@ -95,6 +94,6 @@ func Setup(router *gin.Engine) {
fileGroup.POST("/chunkCheck", middleware.PreAuthorize(nil), controller.NewFile.ChunkCheck)
fileGroup.POST("/chunkUpload", middleware.PreAuthorize(nil), controller.NewFile.ChunkUpload)
fileGroup.POST("/chunkMerge", middleware.PreAuthorize(nil), controller.NewFile.ChunkMerge)
fileGroup.POST("/transferStaticFile", middleware.PreAuthorize(nil), controller.NewCommont.TransferStaticFile)
fileGroup.POST("/transferStaticFile", middleware.PreAuthorize(nil), controller.NewFile.TransferStaticFile)
}
}

View File

@@ -1,36 +1,38 @@
package controller
import (
"fmt"
"strings"
"be.ems/src/framework/config"
commonConstants "be.ems/src/framework/constants/common"
tokenConstants "be.ems/src/framework/constants/token"
"be.ems/src/framework/constants"
"be.ems/src/framework/i18n"
"be.ems/src/framework/utils/ctx"
tokenUtils "be.ems/src/framework/utils/token"
"be.ems/src/framework/vo"
"be.ems/src/framework/vo/result"
commonModel "be.ems/src/modules/common/model"
commonService "be.ems/src/modules/common/service"
"be.ems/src/framework/reqctx"
"be.ems/src/framework/resp"
"be.ems/src/framework/token"
"be.ems/src/modules/common/model"
"be.ems/src/modules/common/service"
systemModelVO "be.ems/src/modules/system/model/vo"
systemService "be.ems/src/modules/system/service"
"github.com/gin-gonic/gin"
)
// 实例化控制层 AccountController 结构体
var NewAccount = &AccountController{
accountService: commonService.NewAccount,
sysLogLoginService: systemService.NewSysLogLoginImpl,
accountService: service.NewAccount,
sysLogLoginService: systemService.NewSysLogLogin,
}
// 账号身份操作处理
//
// PATH /
type AccountController struct {
accountService *commonService.Account // 账号身份操作服务
// 系统登录访问
sysLogLoginService systemService.ISysLogLogin
accountService *service.Account // 账号身份操作服务
sysLogLoginService *systemService.SysLogLogin // 系统登录访问
}
// 系统登录
// Login 系统登录
//
// POST /login
//
@@ -42,62 +44,62 @@ type AccountController struct {
// @Summary System Login
// @Description System Login
// @Router /login [post]
func (s *AccountController) Login(c *gin.Context) {
language := ctx.AcceptLanguage(c)
var loginBody commonModel.LoginBody
if err := c.ShouldBindJSON(&loginBody); err != nil {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
func (s AccountController) Login(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
var body model.LoginBody
if err := c.ShouldBindJSON(&body); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(40422, errMsgs))
return
}
// 当前请求信息
ipaddr, location := ctx.IPAddrLocation(c)
os, browser := ctx.UaOsBrowser(c)
ipaddr, location := reqctx.IPAddrLocation(c)
os, browser := reqctx.UaOsBrowser(c)
// 校验验证码
err := s.accountService.ValidateCaptcha(
loginBody.Code,
loginBody.UUID,
)
// 根据错误信息,创建系统访问记录
if err != nil {
s.sysLogLoginService.CreateSysLogLogin(
loginBody.Username, commonConstants.STATUS_NO, err.Error(),
ipaddr, location, os, browser,
// 校验验证码 根据错误信息,创建系统访问记录
if err := s.accountService.ValidateCaptcha(body.Code, body.UUID); err != nil {
msg := fmt.Sprintf("%s code: %s", err.Error(), body.Code)
s.sysLogLoginService.Insert(
body.Username, constants.STATUS_NO, msg,
[4]string{ipaddr, location, os, browser},
)
c.JSON(200, result.ErrMsg(i18n.TKey(language, err.Error())))
c.JSON(400, resp.CodeMsg(40012, i18n.TKey(language, err.Error())))
return
}
// 登录用户信息
loginUser, err := s.accountService.LoginByUsername(loginBody.Username, loginBody.Password)
loginUser, err := s.accountService.ByUsername(body.Username, body.Password)
if err != nil {
c.JSON(200, result.ErrMsg(i18n.TKey(language, err.Error())))
c.JSON(200, resp.ErrMsg(i18n.TKey(language, err.Error())))
return
}
// 生成令牌,创建系统访问记录
tokenStr := tokenUtils.Create(&loginUser, ipaddr, location, os, browser)
tokenStr := token.Create(&loginUser, [4]string{ipaddr, location, os, browser})
if tokenStr == "" {
c.JSON(200, result.Err(nil))
c.JSON(200, resp.Err(nil))
return
} else {
s.accountService.UpdateLoginDateAndIP(&loginUser)
s.accountService.UpdateLoginDateAndIP(loginUser)
// 登录成功
s.sysLogLoginService.CreateSysLogLogin(
loginBody.Username, commonConstants.STATUS_YES, "app.common.loginSuccess",
ipaddr, location, os, browser,
s.sysLogLoginService.Insert(
body.Username, constants.STATUS_YES, "app.common.loginSuccess",
[4]string{ipaddr, location, os, browser},
)
}
c.JSON(200, result.OkData(map[string]any{
tokenConstants.RESPONSE_FIELD: tokenStr,
c.JSON(200, resp.OkData(map[string]any{
"accessToken": tokenStr,
"tokenType": strings.TrimRight(constants.HEADER_PREFIX, " "),
"expiresIn": (loginUser.ExpireTime - loginUser.LoginTime) / 1000,
"userId": loginUser.UserId,
}))
}
// 登录用户信息
// Me 登录用户信息
//
// GET /getInfo
// GET /me
//
// @Tags common/authorization
// @Accept json
@@ -106,35 +108,35 @@ func (s *AccountController) Login(c *gin.Context) {
// @Security TokenAuth
// @Summary Login User Information
// @Description Login User Information
// @Router /getInfo [get]
func (s *AccountController) Info(c *gin.Context) {
language := ctx.AcceptLanguage(c)
loginUser, err := ctx.LoginUser(c)
// @Router /me [get]
func (s AccountController) Me(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
info, err := reqctx.LoginUser(c)
if err != nil {
c.JSON(401, result.CodeMsg(401, i18n.TKey(language, err.Error())))
c.JSON(401, resp.CodeMsg(40003, err.Error()))
return
}
// 角色权限集合,管理员拥有所有权限
isAdmin := config.IsAdmin(loginUser.UserID)
roles, perms := s.accountService.RoleAndMenuPerms(loginUser.UserID, isAdmin)
// 角色权限集合,系统管理员拥有所有权限
isSystemUser := config.IsSystemUser(info.UserId)
roles, perms := s.accountService.RoleAndMenuPerms(info.UserId, isSystemUser)
loginUser.User.NickName = i18n.TKey(language, loginUser.User.NickName)
loginUser.User.Remark = i18n.TKey(language, loginUser.User.Remark)
loginUser.User.Dept.DeptName = i18n.TKey(language, loginUser.User.Dept.DeptName)
for ri := range loginUser.User.Roles {
loginUser.User.Roles[ri].RoleName = i18n.TKey(language, loginUser.User.Roles[ri].RoleName)
info.User.NickName = i18n.TKey(language, info.User.NickName)
info.User.Remark = i18n.TKey(language, info.User.Remark)
info.User.Dept.DeptName = i18n.TKey(language, info.User.Dept.DeptName)
for ri := range info.User.Roles {
info.User.Roles[ri].RoleName = i18n.TKey(language, info.User.Roles[ri].RoleName)
}
c.JSON(200, result.OkData(map[string]any{
"user": loginUser.User,
c.JSON(200, resp.OkData(map[string]any{
"user": info.User,
"roles": roles,
"permissions": perms,
}))
}
// 登录用户路由信息
// Router 登录用户路由信息
//
// GET /getRouters
// GET /router
//
// @Tags common/authorization
// @Accept json
@@ -143,18 +145,18 @@ func (s *AccountController) Info(c *gin.Context) {
// @Security TokenAuth
// @Summary Login User Routing Information
// @Description Login User Routing Information
// @Router /getRouters [get]
func (s *AccountController) Router(c *gin.Context) {
userID := ctx.LoginUserToUserID(c)
// @Router /router [get]
func (s AccountController) Router(c *gin.Context) {
userId := reqctx.LoginUserToUserID(c)
// 前端路由,管理员拥有所有
isAdmin := config.IsAdmin(userID)
buildMenus := s.accountService.RouteMenus(userID, isAdmin)
// 前端路由,系统管理员拥有所有
isSystemUser := config.IsSystemUser(userId)
buildMenus := s.accountService.RouteMenus(userId, isSystemUser)
// 闭包函数处理多语言
language := ctx.AcceptLanguage(c)
var converI18n func(language string, arr *[]vo.Router)
converI18n = func(language string, arr *[]vo.Router) {
language := reqctx.AcceptLanguage(c)
var converI18n func(language string, arr *[]systemModelVO.Router)
converI18n = func(language string, arr *[]systemModelVO.Router) {
for i := range *arr {
(*arr)[i].Meta.Title = i18n.TKey(language, (*arr)[i].Meta.Title)
if len((*arr)[i].Children) > 0 {
@@ -164,10 +166,10 @@ func (s *AccountController) Router(c *gin.Context) {
}
converI18n(language, &buildMenus)
c.JSON(200, result.OkData(buildMenus))
c.JSON(200, resp.OkData(buildMenus))
}
// 系统登出
// Logout 系统登出
//
// POST /logout
//
@@ -179,25 +181,23 @@ func (s *AccountController) Router(c *gin.Context) {
// @Summary System Logout
// @Description System Logout
// @Router /logout [post]
func (s *AccountController) Logout(c *gin.Context) {
language := ctx.AcceptLanguage(c)
tokenStr := ctx.Authorization(c)
func (s AccountController) Logout(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
tokenStr := reqctx.Authorization(c)
if tokenStr != "" {
// 存在token时记录退出信息
userName := tokenUtils.Remove(tokenStr)
userName := token.Remove(tokenStr)
if userName != "" {
// 当前请求信息
ipaddr, location := ctx.IPAddrLocation(c)
os, browser := ctx.UaOsBrowser(c)
// 创建系统访问记录 退出成功
s.sysLogLoginService.CreateSysLogLogin(
userName, commonConstants.STATUS_YES, "app.common.logoutSuccess",
ipaddr, location, os, browser,
ipaddr, location := reqctx.IPAddrLocation(c)
os, browser := reqctx.UaOsBrowser(c)
// 创建系统访问记录
s.sysLogLoginService.Insert(
userName, constants.STATUS_YES, "app.common.logoutSuccess",
[4]string{ipaddr, location, os, browser},
)
}
}
c.JSON(200, result.OkMsg(i18n.TKey(language, "app.common.logoutSuccess")))
c.JSON(200, resp.OkMsg(i18n.TKey(language, "app.common.logoutSuccess")))
}

View File

@@ -1,34 +1,33 @@
package controller
import (
adminConstants "be.ems/src/framework/constants/admin"
"be.ems/src/framework/constants/common"
tokenConstants "be.ems/src/framework/constants/token"
"strings"
"be.ems/src/framework/constants"
"be.ems/src/framework/i18n"
"be.ems/src/framework/utils/ctx"
"be.ems/src/framework/reqctx"
"be.ems/src/framework/resp"
"be.ems/src/framework/token"
"be.ems/src/framework/utils/machine"
"be.ems/src/framework/utils/regular"
tokenUtils "be.ems/src/framework/utils/token"
"be.ems/src/framework/vo"
"be.ems/src/framework/vo/result"
commonService "be.ems/src/modules/common/service"
"be.ems/src/modules/common/service"
systemService "be.ems/src/modules/system/service"
"github.com/gin-gonic/gin"
)
// 实例化控制层 BootloaderController 结构体
var NewBootloader = &BootloaderController{
accountService: commonService.NewAccount,
sysUserService: systemService.NewSysUserImpl,
accountService: service.NewAccount,
sysUserService: systemService.NewSysUser,
}
// 系统引导初始化
//
// PATH /bootloader
type BootloaderController struct {
accountService *commonService.Account // 账号身份操作服务
// 用户信息服务
sysUserService systemService.ISysUser
accountService *service.Account // 账号身份操作服务
sysUserService *systemService.SysUser // 用户信息服务
}
// 首次引导开始
@@ -38,44 +37,47 @@ func (s *BootloaderController) Start(c *gin.Context) {
// 是否完成引导
launchInfo := machine.LaunchInfo
if launchInfo == nil {
c.JSON(200, result.Err(nil))
c.JSON(200, resp.Err(nil))
return
}
if v, ok := launchInfo[common.LAUNCH_BOOTLOADER]; ok && !v.(bool) {
c.JSON(200, result.ErrMsg("bootloader done"))
if v, ok := launchInfo[constants.LAUNCH_BOOTLOADER]; ok && !v.(bool) {
c.JSON(200, resp.ErrMsg("bootloader done"))
return
}
// 查询用户登录账号
sysUser := s.sysUserService.SelectUserById("1")
if sysUser.UserID != "1" {
c.JSON(200, result.ErrMsg("not found user data"))
sysUser := s.sysUserService.FindById(1)
if sysUser.UserId != 1 {
c.JSON(200, resp.ErrMsg("not found user data"))
return
}
// 登录用户信息
loginUser := vo.LoginUser{
UserID: sysUser.UserID,
DeptID: sysUser.DeptID,
loginUser := token.TokenInfo{
UserId: sysUser.UserId,
DeptId: sysUser.DeptId,
User: sysUser,
Permissions: []string{adminConstants.PERMISSION},
Permissions: []string{constants.SYS_PERMISSION_SYSTEM},
}
// 当前请求信息
ipaddr, location := ctx.IPAddrLocation(c)
os, browser := ctx.UaOsBrowser(c)
ipaddr, location := reqctx.IPAddrLocation(c)
os, browser := reqctx.UaOsBrowser(c)
// 生成令牌,创建系统访问记录
tokenStr := tokenUtils.Create(&loginUser, ipaddr, location, os, browser)
tokenStr := token.Create(&loginUser, [4]string{ipaddr, location, os, browser})
if tokenStr == "" {
c.JSON(200, result.Err(nil))
c.JSON(200, resp.Err(nil))
return
} else {
s.accountService.UpdateLoginDateAndIP(&loginUser)
s.accountService.UpdateLoginDateAndIP(loginUser)
}
c.JSON(200, result.OkData(map[string]any{
tokenConstants.RESPONSE_FIELD: tokenStr,
c.JSON(200, resp.OkData(map[string]any{
"accessToken": tokenStr,
"tokenType": strings.TrimRight(constants.HEADER_PREFIX, " "),
"expiresIn": (loginUser.ExpireTime - loginUser.LoginTime) / 1000,
"userId": loginUser.UserId,
}))
}
@@ -86,23 +88,23 @@ func (s *BootloaderController) Done(c *gin.Context) {
// 是否完成引导
launchInfo := machine.LaunchInfo
if launchInfo == nil {
c.JSON(200, result.Err(nil))
c.JSON(200, resp.Err(nil))
return
}
if v, ok := launchInfo[common.LAUNCH_BOOTLOADER]; ok && !v.(bool) {
c.JSON(200, result.ErrMsg("bootloader done"))
if v, ok := launchInfo[constants.LAUNCH_BOOTLOADER]; ok && !v.(bool) {
c.JSON(200, resp.ErrMsg("bootloader done"))
return
}
// 标记引导完成
if err := machine.Bootloader(false); err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
// 清除授权信息
tokenUtils.Remove(ctx.Authorization(c))
c.JSON(200, result.Ok(nil))
token.Remove(reqctx.Authorization(c))
c.JSON(200, resp.Ok(nil))
}
// 引导系统数据重置
@@ -112,69 +114,69 @@ func (s *BootloaderController) Reset(c *gin.Context) {
// 是否完成引导
launchInfo := machine.LaunchInfo
if launchInfo == nil {
c.JSON(200, result.Err(nil))
c.JSON(200, resp.Err(nil))
return
}
if v, ok := launchInfo[common.LAUNCH_BOOTLOADER]; ok && v.(bool) {
c.JSON(200, result.ErrMsg("bootloader not done"))
if v, ok := launchInfo[constants.LAUNCH_BOOTLOADER]; ok && v.(bool) {
c.JSON(200, resp.ErrMsg("bootloader not done"))
return
}
if err := machine.Reset(); err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
// 清除授权信息
tokenUtils.Remove(ctx.Authorization(c))
c.JSON(200, result.Ok(nil))
token.Remove(reqctx.Authorization(c))
c.JSON(200, resp.Ok(nil))
}
// 账号变更
//
// PUT /account
func (s *BootloaderController) Account(c *gin.Context) {
language := ctx.AcceptLanguage(c)
language := reqctx.AcceptLanguage(c)
var body struct {
UserName string `json:"username" binding:"required"`
Password string `json:"password" binding:"required"`
}
if err := c.ShouldBindJSON(&body); err != nil {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
if !regular.ValidPassword(body.Password) {
// 登录密码至少包含大小写字母、数字、特殊符号且不少于6位
c.JSON(200, result.ErrMsg(i18n.TKey(language, "user.errPasswd")))
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "user.errPasswd")))
return
}
// 是否完成引导
launchInfo := machine.LaunchInfo
if launchInfo == nil {
c.JSON(200, result.Err(nil))
c.JSON(200, resp.Err(nil))
return
}
if v, ok := launchInfo[common.LAUNCH_BOOTLOADER]; ok && !v.(bool) {
c.JSON(200, result.ErrMsg("bootloader done"))
if v, ok := launchInfo[constants.LAUNCH_BOOTLOADER]; ok && !v.(bool) {
c.JSON(200, resp.ErrMsg("bootloader done"))
return
}
// 查询用户登录账号
sysUser := s.sysUserService.SelectUserById("2")
if sysUser.UserID != "2" {
c.JSON(200, result.ErrMsg("not found user data"))
sysUser := s.sysUserService.FindById(2)
if sysUser.UserId != 2 {
c.JSON(200, resp.ErrMsg("not found user data"))
return
}
sysUser.UserName = body.UserName
sysUser.NickName = body.UserName
sysUser.Password = body.Password
sysUser.UpdateBy = ctx.LoginUserToUserName(c)
rows := s.sysUserService.UpdateUser(sysUser)
sysUser.UpdateBy = reqctx.LoginUserToUserName(c)
rows := s.sysUserService.Update(sysUser)
if rows > 0 {
c.JSON(200, result.Ok(nil))
c.JSON(200, resp.Ok(nil))
return
}
c.JSON(200, result.Err(nil))
c.JSON(200, resp.Err(nil))
}

View File

@@ -4,12 +4,11 @@ import (
"time"
"be.ems/src/framework/config"
"be.ems/src/framework/constants/cachekey"
"be.ems/src/framework/constants/captcha"
"be.ems/src/framework/constants"
"be.ems/src/framework/database/redis"
"be.ems/src/framework/logger"
"be.ems/src/framework/redis"
"be.ems/src/framework/resp"
"be.ems/src/framework/utils/parse"
"be.ems/src/framework/vo/result"
systemService "be.ems/src/modules/system/service"
"github.com/gin-gonic/gin"
@@ -18,15 +17,14 @@ import (
// 实例化控制层 CaptchaController 结构体
var NewCaptcha = &CaptchaController{
sysConfigService: systemService.NewSysConfigImpl,
sysConfigService: systemService.NewSysConfig,
}
// 验证码操作处理
//
// PATH /
type CaptchaController struct {
// 参数配置服务
sysConfigService systemService.ISysConfig
sysConfigService *systemService.SysConfig // 参数配置服务
}
// 获取验证码
@@ -43,10 +41,10 @@ type CaptchaController struct {
// @Router /captchaImage [get]
func (s *CaptchaController) Image(c *gin.Context) {
// 从数据库配置获取验证码开关 true开启false关闭
captchaEnabledStr := s.sysConfigService.SelectConfigValueByKey("sys.account.captchaEnabled")
captchaEnabledStr := s.sysConfigService.FindValueByKey("sys.account.captchaEnabled")
captchaEnabled := parse.Boolean(captchaEnabledStr)
if !captchaEnabled {
c.JSON(200, result.Ok(map[string]any{
c.JSON(200, resp.Ok(map[string]any{
"captchaEnabled": captchaEnabled,
}))
return
@@ -61,8 +59,8 @@ func (s *CaptchaController) Image(c *gin.Context) {
}
// 从数据库配置获取验证码类型 math 数值计算 char 字符验证
captchaType := s.sysConfigService.SelectConfigValueByKey("sys.account.captchaType")
if captchaType == captcha.TYPE_MATH {
captchaType := s.sysConfigService.FindValueByKey("sys.account.captchaType")
if captchaType == constants.CAPTCHA_TYPE_MATH {
math := config.Get("mathCaptcha").(map[string]any)
driverCaptcha := &base64Captcha.DriverMath{
//Height png height in pixel.
@@ -87,12 +85,12 @@ func (s *CaptchaController) Image(c *gin.Context) {
} else {
data["uuid"] = id
data["img"] = item.EncodeB64string()
expiration := captcha.EXPIRATION * time.Second
verifyKey = cachekey.CAPTCHA_CODE_KEY + id
expiration := constants.CAPTCHA_EXPIRATION * time.Second
verifyKey = constants.CACHE_CAPTCHA_CODE + ":" + id
redis.SetByExpire("", verifyKey, answer, expiration)
}
}
if captchaType == captcha.TYPE_CHAR {
if captchaType == constants.CAPTCHA_TYPE_CHAR {
char := config.Get("charCaptcha").(map[string]any)
driverCaptcha := &base64Captcha.DriverString{
//Height png height in pixel.
@@ -121,8 +119,8 @@ func (s *CaptchaController) Image(c *gin.Context) {
} else {
data["uuid"] = id
data["img"] = item.EncodeB64string()
expiration := captcha.EXPIRATION * time.Second
verifyKey = cachekey.CAPTCHA_CODE_KEY + id
expiration := constants.CAPTCHA_EXPIRATION * time.Second
verifyKey = constants.CACHE_CAPTCHA_CODE + ":" + id
redis.SetByExpire("", verifyKey, answer, expiration)
}
}
@@ -131,8 +129,8 @@ func (s *CaptchaController) Image(c *gin.Context) {
if config.Env() == "local" {
text, _ := redis.Get("", verifyKey)
data["text"] = text
c.JSON(200, result.Ok(data))
c.JSON(200, resp.Ok(data))
return
}
c.JSON(200, result.Ok(data))
c.JSON(200, resp.Ok(data))
}

View File

@@ -1,37 +1,92 @@
package controller
import (
"crypto/md5"
"crypto/sha1"
"crypto/sha256"
"crypto/sha512"
"encoding/hex"
"fmt"
"hash"
"be.ems/src/framework/i18n"
"be.ems/src/framework/utils/ctx"
"be.ems/src/framework/vo/result"
"be.ems/src/framework/reqctx"
"be.ems/src/framework/resp"
commonService "be.ems/src/modules/common/service"
"github.com/gin-gonic/gin"
)
// 实例化控制层 CommontController 结构体
var NewCommont = &CommontController{
// 实例化控制层 CommonController 结构体
var NewCommon = &CommonController{
commontService: commonService.NewCommont,
}
// 通用请求
//
// PATH /
type CommontController struct {
type CommonController struct {
commontService *commonService.Commont // 通用请求服务
}
// 哈希加密
// Hash 哈希编码
//
// POST /hash
func (s *CommontController) Hash(c *gin.Context) {
c.String(200, "commont Hash")
func (s CommonController) Hash(c *gin.Context) {
var body struct {
Type string `json:"type" binding:"required,oneof=sha1 sha256 sha512 md5"`
Str string `json:"str" binding:"required"`
}
if err := c.ShouldBindJSON(&body); err != nil {
c.JSON(200, gin.H{
"code": 400,
"msg": "参数错误",
})
return
}
var h hash.Hash
var err error
switch body.Type {
case "sha1":
h = sha1.New()
case "sha256":
h = sha256.New()
case "sha512":
h = sha512.New()
case "md5":
h = md5.New()
default:
c.JSON(200, gin.H{
"code": 400,
"msg": fmt.Sprintf("不支持的哈希算法: %s", body.Type),
})
return
}
// 写入需要哈希的数据
if _, err = h.Write([]byte(body.Str)); err != nil {
c.JSON(500, gin.H{
"code": 500,
"msg": "哈希写入错误",
})
return
}
// 计算哈希值的16进制表示
hashed := h.Sum(nil)
text := hex.EncodeToString(hashed)
c.JSON(200, gin.H{
"code": 200,
"msg": "success",
"data": text,
})
}
// 多语言处理
//
// GET /i18n
func (s *CommontController) I18n(c *gin.Context) {
language := ctx.AcceptLanguage(c)
func (s *CommonController) I18n(c *gin.Context) {
language := reqctx.AcceptLanguage(c)
i18nLang := i18n.TKey(language, "i18n")
hello := i18n.TKey(language, "hello")
@@ -57,11 +112,11 @@ func (s *CommontController) I18n(c *gin.Context) {
// @Summary Configuration information for the system
// @Description Configuration information for the system
// @Router /sys-conf [get]
func (s *CommontController) SysConfig(c *gin.Context) {
func (s CommonController) SysConfig(c *gin.Context) {
data := s.commontService.SystemConfigInfo()
// 闭包函数处理多语言
language := ctx.AcceptLanguage(c)
language := reqctx.AcceptLanguage(c)
converI18n := func(language string, arr *map[string]string) {
for k, v := range *arr {
(*arr)[k] = i18n.TKey(language, v)
@@ -69,5 +124,5 @@ func (s *CommontController) SysConfig(c *gin.Context) {
}
converI18n(language, &data)
c.JSON(200, result.OkData(data))
c.JSON(200, resp.OkData(data))
}

View File

@@ -8,14 +8,13 @@ import (
"strings"
"be.ems/src/framework/config"
"be.ems/src/framework/constants/uploadsubpath"
"be.ems/src/framework/constants"
"be.ems/src/framework/i18n"
"be.ems/src/framework/utils/ctx"
"be.ems/src/framework/reqctx"
"be.ems/src/framework/resp"
"be.ems/src/framework/utils/file"
"be.ems/src/framework/vo/result"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
)
// 实例化控制层 FileController 结构体
@@ -30,16 +29,16 @@ type FileController struct{}
//
// GET /download/:filePath
func (s *FileController) Download(c *gin.Context) {
language := ctx.AcceptLanguage(c)
language := reqctx.AcceptLanguage(c)
filePath := c.Param("filePath")
if len(filePath) < 8 {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
// base64解析出地址
decodedBytes, err := base64.StdEncoding.DecodeString(filePath)
if err != nil {
c.JSON(400, result.CodeMsg(400, err.Error()))
c.JSON(400, resp.CodeMsg(400, err.Error()))
return
}
routerPath := string(decodedBytes)
@@ -48,7 +47,7 @@ func (s *FileController) Download(c *gin.Context) {
headerRange := c.GetHeader("Range")
resultMap, err := file.ReadUploadFileStream(routerPath, headerRange)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
@@ -83,29 +82,29 @@ func (s *FileController) Download(c *gin.Context) {
// @Description Upload a file, interface param use <fileName>
// @Router /file/upload [post]
func (s *FileController) Upload(c *gin.Context) {
language := ctx.AcceptLanguage(c)
language := reqctx.AcceptLanguage(c)
// 上传的文件
formFile, err := c.FormFile("file")
if err != nil {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
// 子路径
subPath := c.PostForm("subPath")
if _, ok := uploadsubpath.UploadSubpath[subPath]; !ok {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
if _, ok := constants.UPLOAD_SUB_PATH[subPath]; !ok {
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
// 上传文件转存
upFilePath, err := file.TransferUploadFile(formFile, subPath, nil)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
newFileName := upFilePath[strings.LastIndex(upFilePath, "/")+1:]
c.JSON(200, result.OkData(map[string]string{
c.JSON(200, resp.OkData(map[string]string{
"url": "//" + c.Request.Host + upFilePath,
"fileName": upFilePath,
"newFileName": newFileName,
@@ -127,7 +126,7 @@ func (s *FileController) Upload(c *gin.Context) {
// @Description Slice file checking
// @Router /file/chunkCheck [post]
func (s *FileController) ChunkCheck(c *gin.Context) {
language := ctx.AcceptLanguage(c)
language := reqctx.AcceptLanguage(c)
var body struct {
// 唯一标识
Identifier string `json:"identifier" binding:"required"`
@@ -136,17 +135,17 @@ func (s *FileController) ChunkCheck(c *gin.Context) {
}
err := c.ShouldBindJSON(&body)
if err != nil {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
// 读取标识目录
chunks, err := file.ChunkCheckFile(body.Identifier, body.FileName)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
c.JSON(200, result.OkData(chunks))
c.JSON(200, resp.OkData(chunks))
}
// 切片文件合并
@@ -163,7 +162,7 @@ func (s *FileController) ChunkCheck(c *gin.Context) {
// @Description Slice file merge
// @Router /file/chunkMerge [post]
func (s *FileController) ChunkMerge(c *gin.Context) {
language := ctx.AcceptLanguage(c)
language := reqctx.AcceptLanguage(c)
var body struct {
// 唯一标识
Identifier string `json:"identifier" binding:"required"`
@@ -174,23 +173,23 @@ func (s *FileController) ChunkMerge(c *gin.Context) {
}
err := c.ShouldBindJSON(&body)
if err != nil {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
if _, ok := uploadsubpath.UploadSubpath[body.SubPath]; !ok {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
if _, ok := constants.UPLOAD_SUB_PATH[body.SubPath]; !ok {
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
// 切片文件合并
mergeFilePath, err := file.ChunkMergeFile(body.Identifier, body.FileName, body.SubPath)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
newFileName := mergeFilePath[strings.LastIndex(mergeFilePath, "/")+1:]
c.JSON(200, result.OkData(map[string]string{
c.JSON(200, resp.OkData(map[string]string{
"url": "//" + c.Request.Host + mergeFilePath,
"fileName": mergeFilePath,
"newFileName": newFileName,
@@ -214,7 +213,7 @@ func (s *FileController) ChunkMerge(c *gin.Context) {
// @Description Sliced file upload
// @Router /file/chunkUpload [post]
func (s *FileController) ChunkUpload(c *gin.Context) {
language := ctx.AcceptLanguage(c)
language := reqctx.AcceptLanguage(c)
// 切片编号
index := c.PostForm("index")
// 切片唯一标识
@@ -222,31 +221,31 @@ func (s *FileController) ChunkUpload(c *gin.Context) {
// 上传的文件
formFile, err := c.FormFile("file")
if index == "" || identifier == "" || err != nil {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
return
}
// 上传文件转存
chunkFilePath, err := file.TransferChunkUploadFile(formFile, index, identifier)
if err != nil {
c.JSON(200, result.ErrMsg(err.Error()))
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
c.JSON(206, result.OkData(chunkFilePath))
c.JSON(206, resp.OkData(chunkFilePath))
}
// 转存指定对应文件到静态目录
//
// POST /transferStaticFile
func (s *CommontController) TransferStaticFile(c *gin.Context) {
language := ctx.AcceptLanguage(c)
func (s *FileController) TransferStaticFile(c *gin.Context) {
var body struct {
UploadPath string `json:"uploadPath" binding:"required"`
StaticPath string `json:"staticPath" binding:"required"`
Language string `json:"language" binding:"required"`
}
if err := c.ShouldBindBodyWith(&body, binding.JSON); err != nil {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(40422, errMsgs))
return
}
@@ -257,7 +256,7 @@ func (s *CommontController) TransferStaticFile(c *gin.Context) {
static := config.Get("staticFile.default").(map[string]any)
dir, err := filepath.Abs(static["dir"].(string))
if err != nil {
c.JSON(400, result.CodeMsg(400, err.Error()))
c.JSON(400, resp.CodeMsg(400, err.Error()))
return
}
@@ -267,10 +266,10 @@ func (s *CommontController) TransferStaticFile(c *gin.Context) {
err = file.CopyUploadFile(body.UploadPath, newFile)
if err != nil {
c.JSON(400, result.CodeMsg(400, err.Error()))
c.JSON(400, resp.CodeMsg(400, err.Error()))
return
}
urlPath := strings.Replace(newFile, dir, static["prefix"].(string), 1)
c.JSON(200, result.OkData(filepath.ToSlash(urlPath)))
c.JSON(200, resp.OkData(filepath.ToSlash(urlPath)))
}

View File

@@ -4,7 +4,7 @@ import (
"fmt"
libGlobal "be.ems/lib/global"
"be.ems/src/framework/vo/result"
"be.ems/src/framework/resp"
"github.com/gin-gonic/gin"
)
@@ -32,6 +32,6 @@ func (s *IndexController) Handler(c *gin.Context) {
name := "OMC"
version := libGlobal.Version
// str := "欢迎使用%s核心网管理平台当前版本%s请通过前台地址访问。"
str := "Welcome to the %s Core Network Management Platform, current version: %s, please access via the frontend address."
c.JSON(200, result.OkMsg(fmt.Sprintf(str, name, version)))
str := "%s Core Network Management, current version: %s"
c.JSON(200, resp.OkMsg(fmt.Sprintf(str, name, version)))
}

View File

@@ -1,13 +1,15 @@
package controller
import (
commonConstants "be.ems/src/framework/constants/common"
"fmt"
"be.ems/src/framework/constants"
"be.ems/src/framework/i18n"
"be.ems/src/framework/utils/ctx"
"be.ems/src/framework/reqctx"
"be.ems/src/framework/resp"
"be.ems/src/framework/utils/regular"
"be.ems/src/framework/vo/result"
commonModel "be.ems/src/modules/common/model"
commonService "be.ems/src/modules/common/service"
"be.ems/src/modules/common/model"
"be.ems/src/modules/common/service"
systemService "be.ems/src/modules/system/service"
"github.com/gin-gonic/gin"
@@ -15,77 +17,77 @@ import (
// 实例化控制层 RegisterController 结构体
var NewRegister = &RegisterController{
registerService: commonService.NewRegisterImpl,
sysLogLoginService: systemService.NewSysLogLoginImpl,
registerService: service.NewRegister,
sysLogLoginService: systemService.NewSysLogLogin,
}
// 账号注册操作处理
//
// PATH /
type RegisterController struct {
// 账号注册操作服务
registerService commonService.IRegister
// 系统登录访问
sysLogLoginService systemService.ISysLogLogin
registerService *service.Register // 账号注册操作服务
sysLogLoginService *systemService.SysLogLogin // 系统登录访问服务
}
// 账号注册
//
// GET /register
func (s *RegisterController) Register(c *gin.Context) {
language := ctx.AcceptLanguage(c)
var registerBody commonModel.RegisterBody
if err := c.ShouldBindJSON(&registerBody); err != nil {
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
language := reqctx.AcceptLanguage(c)
var body model.RegisterBody
if err := c.ShouldBindJSON(&body); err != nil {
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
c.JSON(422, resp.CodeMsg(40422, errMsgs))
return
}
// 判断必传参数
if !regular.ValidUsername(registerBody.Username) {
if !regular.ValidUsername(body.Username) {
// 账号不能以数字开头可包含大写小写字母数字且不少于5位
c.JSON(200, result.ErrMsg(i18n.TKey(language, "register.errUsername")))
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "register.errUsername")))
return
}
if !regular.ValidPassword(registerBody.Password) {
if !regular.ValidPassword(body.Password) {
// 登录密码至少包含大小写字母、数字、特殊符号且不少于6位
c.JSON(200, result.ErrMsg(i18n.TKey(language, "register.errPasswd")))
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "register.errPasswd")))
return
}
if registerBody.Password != registerBody.ConfirmPassword {
if body.Password != body.ConfirmPassword {
// 用户确认输入密码不一致
c.JSON(200, result.ErrMsg(i18n.TKey(language, "register.errPasswdNotEq")))
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "register.errPasswdNotEq")))
return
}
// 当前请求信息
ipaddr, location := ctx.IPAddrLocation(c)
os, browser := ctx.UaOsBrowser(c)
ipaddr, location := reqctx.IPAddrLocation(c)
os, browser := reqctx.UaOsBrowser(c)
// 校验验证码
err := s.registerService.ValidateCaptcha(
registerBody.Code,
registerBody.UUID,
body.Code,
body.UUID,
)
// 根据错误信息,创建系统访问记录
if err != nil {
s.sysLogLoginService.CreateSysLogLogin(
registerBody.Username, commonConstants.STATUS_NO, err.Error(),
ipaddr, location, os, browser,
msg := err.Error() + " code: " + body.Code
s.sysLogLoginService.Insert(
body.Username, constants.STATUS_NO, msg,
[4]string{ipaddr, location, os, browser},
)
c.JSON(200, result.ErrMsg(err.Error()))
c.JSON(200, resp.ErrMsg(err.Error()))
return
}
userID, err := s.registerService.ByUserName(registerBody.Username, registerBody.Password, registerBody.UserType)
userId, err := s.registerService.ByUserName(body.Username, body.Password)
if err == nil {
msg := i18n.TTemplate(language, "register.successMsg", map[string]any{"name": registerBody.Username, "id": userID})
s.sysLogLoginService.CreateSysLogLogin(
registerBody.Username, commonConstants.STATUS_YES, msg,
ipaddr, location, os, browser,
msg := i18n.TTemplate(language, "register.successMsg", map[string]any{"name": body.Username, "id": userId})
s.sysLogLoginService.Insert(
body.Username, constants.STATUS_YES, msg,
[4]string{ipaddr, location, os, browser},
)
// 注册成功
c.JSON(200, result.OkMsg(i18n.TKey(language, "register.success")))
c.JSON(200, resp.OkMsg(i18n.TKey(language, "register.success")))
return
}
c.JSON(200, result.ErrMsg(err.Error()))
c.JSON(200, resp.ErrMsg(err.Error()))
}

View File

@@ -5,41 +5,35 @@ import (
"time"
"be.ems/src/framework/config"
adminConstants "be.ems/src/framework/constants/admin"
"be.ems/src/framework/constants/cachekey"
"be.ems/src/framework/constants/common"
"be.ems/src/framework/redis"
"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"
"be.ems/src/framework/vo"
"be.ems/src/modules/system/model"
systemModelVO "be.ems/src/modules/system/model/vo"
systemService "be.ems/src/modules/system/service"
)
// 实例化服务层 Account 结构体
var NewAccount = &Account{
sysUserService: systemService.NewSysUserImpl,
sysConfigService: systemService.NewSysConfigImpl,
sysRoleService: systemService.NewSysRoleImpl,
sysMenuService: systemService.NewSysMenuImpl,
sysUserService: systemService.NewSysUser,
sysConfigService: systemService.NewSysConfig,
sysRoleService: systemService.NewSysRole,
sysMenuService: systemService.NewSysMenu,
}
// 账号身份操作服务 服务层处理
type Account struct {
// 用户信息服务
sysUserService systemService.ISysUser
// 参数配置服务
sysConfigService systemService.ISysConfig
// 角色服务
sysRoleService systemService.ISysRole
// 菜单服务
sysMenuService systemService.ISysMenu
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.SelectConfigValueByKey("sys.account.captchaEnabled")
captchaEnabledStr := s.sysConfigService.FindValueByKey("sys.account.captchaEnabled")
if !parse.Boolean(captchaEnabledStr) {
return nil
}
@@ -47,13 +41,13 @@ func (s *Account) ValidateCaptcha(code, uuid string) error {
// 验证码信息错误
return fmt.Errorf("captcha.err")
}
verifyKey := cachekey.CAPTCHA_CODE_KEY + uuid
verifyKey := constants.CACHE_CAPTCHA_CODE + ":" + uuid
captcha, _ := redis.Get("", verifyKey)
if captcha == "" {
// 验证码已失效
return fmt.Errorf("captcha.errValid")
}
redis.Del("", verifyKey)
_ = redis.Del("", verifyKey)
if captcha != code {
// 验证码错误
return fmt.Errorf("captcha.err")
@@ -61,133 +55,122 @@ func (s *Account) ValidateCaptcha(code, uuid string) error {
return nil
}
// LoginByUsername 登录创建用户信息
func (s *Account) LoginByUsername(username, password string) (vo.LoginUser, error) {
loginUser := vo.LoginUser{}
// ByUsername 登录创建用户信息
func (s Account) ByUsername(username, password string) (token.TokenInfo, error) {
tokenInfo := token.TokenInfo{}
// 检查密码重试次数
retrykey, retryCount, lockTime, err := s.passwordRetryCount(username)
retryKey, retryCount, lockTime, err := s.passwordRetryCount(username)
if err != nil {
return loginUser, err
return tokenInfo, err
}
// 查询用户登录账号
sysUser := s.sysUserService.SelectUserByUserName(username)
sysUser := s.sysUserService.FindByUserName(username)
if sysUser.UserName != username {
return loginUser, fmt.Errorf("login.errNameOrPasswd")
return tokenInfo, fmt.Errorf("login.errNameOrPasswd")
}
if sysUser.DelFlag == common.STATUS_YES {
// 对不起,您的账号已被删除
return loginUser, fmt.Errorf("login.errDelFlag")
if sysUser.DelFlag == constants.STATUS_YES {
return tokenInfo, fmt.Errorf("login.errDelFlag")
}
if sysUser.Status == common.STATUS_NO {
return loginUser, fmt.Errorf("login.errStatus")
if sysUser.StatusFlag == constants.STATUS_NO {
return tokenInfo, fmt.Errorf("login.errStatus")
}
// 检验用户密码
compareBool := crypto.BcryptCompare(password, sysUser.Password)
if !compareBool {
redis.SetByExpire("", retrykey, retryCount+1, lockTime)
// 用户不存在或密码错误
return loginUser, fmt.Errorf("login.errNameOrPasswd")
if compareBool {
s.CleanLoginRecordCache(sysUser.UserName) // 清除错误记录次数
} else {
// 清除错误记录次数
s.ClearLoginRecordCache(username)
_ = redis.SetByExpire("", retryKey, retryCount+1, lockTime)
return tokenInfo, fmt.Errorf("login.errNameOrPasswd")
}
// 登录用户信息
loginUser.UserID = sysUser.UserID
loginUser.DeptID = sysUser.DeptID
loginUser.User = sysUser
tokenInfo.UserId = sysUser.UserId
tokenInfo.DeptId = sysUser.DeptId
tokenInfo.User = sysUser
// 用户权限组标识
isAdmin := config.IsAdmin(sysUser.UserID)
if isAdmin {
loginUser.Permissions = []string{adminConstants.PERMISSION}
if config.IsSystemUser(sysUser.UserId) {
tokenInfo.Permissions = []string{constants.SYS_PERMISSION_SYSTEM}
} else {
perms := s.sysMenuService.SelectMenuPermsByUserId(sysUser.UserID)
loginUser.Permissions = parse.RemoveDuplicates(perms)
perms := s.sysMenuService.FindPermsByUserId(sysUser.UserId)
tokenInfo.Permissions = parse.RemoveDuplicates(perms)
}
return loginUser, nil
return tokenInfo, nil
}
// UpdateLoginDateAndIP 更新登录时间和IP
func (s *Account) UpdateLoginDateAndIP(loginUser *vo.LoginUser) bool {
sysUser := loginUser.User
userInfo := model.SysUser{
UserID: sysUser.UserID,
LoginIP: sysUser.LoginIP,
LoginDate: sysUser.LoginDate,
UpdateBy: sysUser.UserName,
Sex: sysUser.Sex,
PhoneNumber: sysUser.PhoneNumber,
Email: sysUser.Email,
Remark: sysUser.Remark,
}
rows := s.sysUserService.UpdateUser(userInfo)
return rows > 0
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
}
// ClearLoginRecordCache 清除错误记录次数
func (s *Account) ClearLoginRecordCache(username string) bool {
cacheKey := cachekey.PWD_ERR_CNT_KEY + username
hasKey, _ := redis.Has("", cacheKey)
if hasKey {
delOk, _ := redis.Del("", cacheKey)
return delOk
// 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) {
func (s Account) passwordRetryCount(userName string) (string, int64, time.Duration, error) {
// 从数据库配置获取登录次数和错误锁定时间
maxRetryCountStr := s.sysConfigService.SelectConfigValueByKey("sys.user.maxRetryCount")
lockTimeStr := s.sysConfigService.SelectConfigValueByKey("sys.user.lockTime")
maxRetryCountStr := s.sysConfigService.FindValueByKey("sys.user.maxRetryCount")
lockTimeStr := s.sysConfigService.FindValueByKey("sys.user.lockTime")
// 验证登录次数和错误锁定时间
maxRetryCount := parse.Number(maxRetryCountStr)
lockTime := parse.Number(lockTimeStr)
// 验证登录次数和错误锁定时间
// maxRetryCount := config.Get("user.password.maxRetryCount").(int)
// lockTime := config.Get("user.password.lockTime").(int)
// 验证缓存记录次数
retrykey := cachekey.PWD_ERR_CNT_KEY + username
retryCount, err := redis.Get("", retrykey)
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 >= maxRetryCount {
// 密码输入错误多次,帐户已被锁定
errorMsg := fmt.Errorf("login.errRetryPasswd")
return retrykey, retryCountInt64, time.Duration(lockTime) * time.Minute, errorMsg
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
return retryKey, retryCountInt64, time.Duration(lockTime) * time.Minute, nil
}
// RoleAndMenuPerms 角色和菜单数据权限
func (s *Account) RoleAndMenuPerms(userId string, isAdmin bool) ([]string, []string) {
if isAdmin {
return []string{adminConstants.ROLE_KEY}, []string{adminConstants.PERMISSION}
} else {
// 角色key
roleGroup := []string{}
roles := s.sysRoleService.SelectRoleListByUserId(userId)
for _, role := range roles {
roleGroup = append(roleGroup, role.RoleKey)
}
// 菜单权限key
perms := s.sysMenuService.SelectMenuPermsByUserId(userId)
return parse.RemoveDuplicates(roleGroup), parse.RemoveDuplicates(perms)
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 string, isAdmin bool) []vo.Router {
var buildMenus []vo.Router
if isAdmin {
menus := s.sysMenuService.SelectMenuTreeByUserId("*")
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.SelectMenuTreeByUserId(userId)
menus := s.sysMenuService.BuildTreeMenusByUserId(userId)
buildMenus = s.sysMenuService.BuildRouteMenus(menus, "")
}
return buildMenus

View File

@@ -5,23 +5,21 @@ import (
"be.ems/lib/global"
"be.ems/src/framework/config"
"be.ems/src/framework/constants/common"
"be.ems/src/framework/constants"
"be.ems/src/framework/utils/machine"
systemService "be.ems/src/modules/system/service"
)
// 实例化服务层 Commont 结构体
var NewCommont = &Commont{
sysUserService: systemService.NewSysUserImpl,
sysConfigService: systemService.NewSysConfigImpl,
sysUserService: systemService.NewSysUser,
sysConfigService: systemService.NewSysConfig,
}
// 通用请求 服务层处理
type Commont struct {
// 用户信息服务
sysUserService systemService.ISysUser
// 参数配置服务
sysConfigService systemService.ISysConfig
sysUserService *systemService.SysUser // 用户信息服务
sysConfigService *systemService.SysConfig // 参数配置服务
}
// SystemConfigInfo 系统配置信息
@@ -33,13 +31,13 @@ func (s *Commont) SystemConfigInfo() map[string]string {
// 系统首次使用标记
launchInfo := machine.LaunchInfo
if launchInfo != nil {
if v, ok := launchInfo[common.LAUNCH_BOOTLOADER]; ok {
infoMap[common.LAUNCH_BOOTLOADER] = fmt.Sprint(v)
if v, ok := launchInfo[constants.LAUNCH_BOOTLOADER]; ok {
infoMap[constants.LAUNCH_BOOTLOADER] = fmt.Sprint(v)
} else {
infoMap[common.LAUNCH_BOOTLOADER] = "true"
infoMap[constants.LAUNCH_BOOTLOADER] = "true"
}
} else {
infoMap[common.LAUNCH_BOOTLOADER] = "true"
infoMap[constants.LAUNCH_BOOTLOADER] = "true"
}
// 用户登录认证
infoMap["loginAuth"] = fmt.Sprint(config.Get("user.loginAuth"))
@@ -48,36 +46,36 @@ func (s *Commont) SystemConfigInfo() map[string]string {
// 序列号
infoMap["serialNum"] = fmt.Sprint(config.Get("omc.sn"))
// 获取LOGO类型
logoType := s.sysConfigService.SelectConfigValueByKey("sys.logo.type")
logoType := s.sysConfigService.FindValueByKey("sys.logo.type")
infoMap["logoType"] = logoType
// 获取LOGO文件
filePathIcon := s.sysConfigService.SelectConfigValueByKey("sys.logo.filePathIcon")
filePathIcon := s.sysConfigService.FindValueByKey("sys.logo.filePathIcon")
infoMap["filePathIcon"] = filePathIcon
filePathBrand := s.sysConfigService.SelectConfigValueByKey("sys.logo.filePathBrand")
filePathBrand := s.sysConfigService.FindValueByKey("sys.logo.filePathBrand")
infoMap["filePathBrand"] = filePathBrand
// 获取系统名称
title := s.sysConfigService.SelectConfigValueByKey("sys.title")
title := s.sysConfigService.FindValueByKey("sys.title")
infoMap["title"] = title
// 获取版权声明
copyright := s.sysConfigService.SelectConfigValueByKey("sys.copyright")
copyright := s.sysConfigService.FindValueByKey("sys.copyright")
infoMap["copyright"] = copyright
// 获取是否开启用户注册功能
registerUser := s.sysConfigService.SelectConfigValueByKey("sys.account.registerUser")
registerUser := s.sysConfigService.FindValueByKey("sys.account.registerUser")
infoMap["registerUser"] = registerUser
// 获取登录界面背景
loginBackground := s.sysConfigService.SelectConfigValueByKey("sys.loginBackground")
loginBackground := s.sysConfigService.FindValueByKey("sys.loginBackground")
infoMap["loginBackground"] = loginBackground
// 系统设置-官网网址
officialUrl := s.sysConfigService.SelectConfigValueByKey("sys.officialUrl")
officialUrl := s.sysConfigService.FindValueByKey("sys.officialUrl")
infoMap["officialUrl"] = officialUrl
// 系统设置-系统使用文档
helpDoc := s.sysConfigService.SelectConfigValueByKey("sys.helpDoc")
helpDoc := s.sysConfigService.FindValueByKey("sys.helpDoc")
infoMap["helpDoc"] = helpDoc
// 国际化切换
i18nOpen := s.sysConfigService.SelectConfigValueByKey("sys.i18n.open")
i18nOpen := s.sysConfigService.FindValueByKey("sys.i18n.open")
infoMap["i18nOpen"] = i18nOpen
// 国际化默认语言
i18nDefault := s.sysConfigService.SelectConfigValueByKey("sys.i18n.default")
i18nDefault := s.sysConfigService.FindValueByKey("sys.i18n.default")
infoMap["i18nDefault"] = i18nDefault
return infoMap
}

View File

@@ -1,10 +1,92 @@
package service
// 账号注册操作处理 服务层接口
type IRegister interface {
// ValidateCaptcha 校验验证码
ValidateCaptcha(code, uuid string) error
import (
"fmt"
// ByUserName 账号注册
ByUserName(username, password, userType string) (string, error)
"be.ems/src/framework/constants"
"be.ems/src/framework/database/redis"
"be.ems/src/framework/utils/parse"
systemModel "be.ems/src/modules/system/model"
systemService "be.ems/src/modules/system/service"
)
// 实例化服务层 Register 结构体
var NewRegister = &Register{
sysUserService: systemService.NewSysUser,
sysConfigService: systemService.NewSysConfig,
}
// 账号注册操作处理 服务层处理
type Register struct {
sysUserService *systemService.SysUser // 用户信息服务
sysConfigService *systemService.SysConfig // 参数配置服务
}
// ValidateCaptcha 校验验证码
func (s Register) 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("verification code information error")
}
verifyKey := constants.CACHE_CAPTCHA_CODE + ":" + uuid
captcha, err := redis.Get("", verifyKey)
if err != nil {
return fmt.Errorf("the verification code has expired")
}
redis.Del("", verifyKey)
if captcha != code {
return fmt.Errorf("verification code error")
}
return nil
}
// ByUserName 账号注册
func (s Register) ByUserName(username, password string) (int64, error) {
// 是否开启用户注册功能 true开启false关闭
registerUserStr := s.sysConfigService.FindValueByKey("sys.account.registerUser")
captchaEnabled := parse.Boolean(registerUserStr)
if !captchaEnabled {
return 0, fmt.Errorf("failed to register user [%s]. Sorry, the system has closed the external user registration channel", username)
}
// 检查用户登录账号是否唯一
uniqueUserName := s.sysUserService.CheckUniqueByUserName(username, 0)
if !uniqueUserName {
return 0, fmt.Errorf("failed to register user [%s], registered account already exists", username)
}
sysUser := systemModel.SysUser{
UserName: username,
NickName: username, // 昵称使用名称账号
Password: password, // 原始密码
Sex: "0", // 性别未选择
StatusFlag: constants.STATUS_YES, // 账号状态激活
DeptId: 100, // 归属部门为根节点
CreateBy: "register", // 创建来源
}
// 新增用户的角色管理
sysUser.RoleIds = s.registerRoleInit()
// 新增用户的岗位管理
sysUser.PostIds = s.registerPostInit()
insertId := s.sysUserService.Insert(sysUser)
if insertId > 0 {
return insertId, nil
}
return 0, fmt.Errorf("failed to register user [%s]. Please contact the system administrator", username)
}
// registerRoleInit 注册初始角色
func (s Register) registerRoleInit() []int64 {
return []int64{}
}
// registerPostInit 注册初始岗位
func (s Register) registerPostInit() []int64 {
return []int64{}
}

View File

@@ -1,106 +0,0 @@
package service
import (
"fmt"
"be.ems/src/framework/constants/cachekey"
"be.ems/src/framework/constants/common"
"be.ems/src/framework/redis"
"be.ems/src/framework/utils/parse"
systemModel "be.ems/src/modules/system/model"
systemService "be.ems/src/modules/system/service"
)
// 实例化服务层 RegisterImpl 结构体
var NewRegisterImpl = &RegisterImpl{
sysUserService: systemService.NewSysUserImpl,
sysConfigService: systemService.NewSysConfigImpl,
sysRoleService: systemService.NewSysRoleImpl,
}
// 账号注册操作处理 服务层处理
type RegisterImpl struct {
// 用户信息服务
sysUserService systemService.ISysUser
// 参数配置服务
sysConfigService systemService.ISysConfig
// 角色服务
sysRoleService systemService.ISysRole
}
// ValidateCaptcha 校验验证码
func (s *RegisterImpl) ValidateCaptcha(code, uuid string) error {
// 验证码检查,从数据库配置获取验证码开关 true开启false关闭
captchaEnabledStr := s.sysConfigService.SelectConfigValueByKey("sys.account.captchaEnabled")
if !parse.Boolean(captchaEnabledStr) {
return nil
}
if code == "" || uuid == "" {
return fmt.Errorf("verification code information error")
}
verifyKey := cachekey.CAPTCHA_CODE_KEY + uuid
captcha, err := redis.Get("", verifyKey)
if err != nil {
return fmt.Errorf("the verification code has expired")
}
redis.Del("", verifyKey)
if captcha != code {
return fmt.Errorf("verification code error")
}
return nil
}
// ByUserName 账号注册
func (s *RegisterImpl) ByUserName(username, password, userType string) (string, error) {
// 是否开启用户注册功能 true开启false关闭
registerUserStr := s.sysConfigService.SelectConfigValueByKey("sys.account.registerUser")
captchaEnabled := parse.Boolean(registerUserStr)
if !captchaEnabled {
return "", fmt.Errorf("failed to register user [%s]. Sorry, the system has closed the external user registration channel", username)
}
// 检查用户登录账号是否唯一
uniqueUserName := s.sysUserService.CheckUniqueUserName(username, "")
if !uniqueUserName {
return "", fmt.Errorf("failed to register user [%s], registered account already exists", username)
}
sysUser := systemModel.SysUser{
UserName: username,
NickName: username, // 昵称使用名称账号
Password: password, // 原始密码
Status: common.STATUS_YES, // 账号状态激活
DeptID: "100", // 归属部门为根节点
CreateBy: "register", // 创建来源
}
// 标记用户类型
if userType == "" {
sysUser.UserType = "sys"
}
// 新增用户的角色管理
sysUser.RoleIDs = s.registerRoleInit(userType)
// 新增用户的岗位管理
sysUser.PostIDs = s.registerPostInit(userType)
insertId := s.sysUserService.InsertUser(sysUser)
if insertId != "" {
return insertId, nil
}
return "", fmt.Errorf("failed to register user [%s]. Please contact the system administrator", username)
}
// registerRoleInit 注册初始角色
func (s *RegisterImpl) registerRoleInit(userType string) []string {
if userType == "sys" {
return []string{}
}
return []string{}
}
// registerPostInit 注册初始岗位
func (s *RegisterImpl) registerPostInit(userType string) []string {
if userType == "sys" {
return []string{}
}
return []string{}
}