优化
This commit is contained in:
@@ -20,10 +20,10 @@ import (
|
||||
kratoshttp "github.com/go-kratos/kratos/v3/transport/http"
|
||||
)
|
||||
|
||||
func NewGinEngine(runtime *conf.Runtime, system *service.SystemService, access *service.AccessService, authority *handler.Authority, menu *handler.Menu, api *handler.API, permission *handler.Permission, organization *handler.Organization, announcement *handler.Announcement, email *handler.Email, task *handler.Task, media *handler.Media, auditHandler *handler.Audit, export *handler.Export, version *handler.Version, dictionary *handler.Dictionary, parameter *handler.Parameter, apiToken *handler.APIToken, systemConfig *handler.SystemConfig, publicHandler *handler.Public, user *handler.User, navigation *handler.Navigation, session *handler.Session, settings *service.SettingsService, audit *service.AuditService, logger *slog.Logger) *gin.Engine {
|
||||
func NewGinEngine(runtime *conf.Runtime, access *service.AccessService, authority *handler.Authority, menu *handler.Menu, api *handler.API, permission *handler.Permission, organization *handler.Organization, announcement *handler.Announcement, email *handler.Email, task *handler.Task, media *handler.Media, auditHandler *handler.Audit, export *handler.Export, version *handler.Version, dictionary *handler.Dictionary, parameter *handler.Parameter, apiToken *handler.APIToken, systemConfig *handler.SystemConfig, publicHandler *handler.Public, user *handler.User, navigation *handler.Navigation, session *handler.Session, settings *service.SettingsService, audit *service.AuditService, logger *slog.Logger) *gin.Engine {
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
engine := gin.New()
|
||||
engine.Use(servermiddleware.RequestMeta(), servermiddleware.Recovery(audit, logger), servermiddleware.AccessLog(runtime, logger), servermiddleware.ErrorAudit(audit), servermiddleware.SecurityRateLimit(system, settings), servermiddleware.OperationAudit(runtime, audit))
|
||||
engine.Use(servermiddleware.RequestMeta(), servermiddleware.Recovery(audit, logger), servermiddleware.AccessLog(runtime, logger), servermiddleware.ErrorAudit(audit), servermiddleware.SecurityRateLimit(settings), servermiddleware.OperationAudit(runtime, audit))
|
||||
|
||||
prefix := ""
|
||||
config := runtime.Admin()
|
||||
|
||||
@@ -16,12 +16,12 @@ import (
|
||||
)
|
||||
|
||||
type Export struct {
|
||||
system *service.SystemService
|
||||
service *service.ExportService
|
||||
settings *service.SettingsService
|
||||
service *service.ExportService
|
||||
}
|
||||
|
||||
func NewExport(system *service.SystemService, service *service.ExportService) *Export {
|
||||
return &Export{system: system, service: service}
|
||||
func NewExport(settings *service.SettingsService, export *service.ExportService) *Export {
|
||||
return &Export{settings: settings, service: export}
|
||||
}
|
||||
|
||||
type exportToken struct {
|
||||
@@ -153,7 +153,7 @@ func (h *Export) Issue(blank bool) gin.HandlerFunc {
|
||||
}
|
||||
token := strings.ReplaceAll(uuid.NewString(), "-", "")
|
||||
raw, _ := json.Marshal(exportToken{TemplateID: templateID, Params: exportParams(c.Request.URL.Query()), Blank: blank})
|
||||
if err := h.system.CacheSet(c.Request.Context(), "export:"+token, string(raw), 30*time.Minute); err != nil {
|
||||
if err := h.settings.CacheSet(c.Request.Context(), "export:"+token, string(raw), 30*time.Minute); err != nil {
|
||||
httpx.Fail(c, "导出令牌创建失败")
|
||||
return
|
||||
}
|
||||
@@ -196,7 +196,7 @@ func (h *Export) Download(expectBlank bool) gin.HandlerFunc {
|
||||
httpx.Fail(c, "导出token不能为空")
|
||||
return
|
||||
}
|
||||
raw, ok, err := h.system.CacheGet(c.Request.Context(), "export:"+token)
|
||||
raw, ok, err := h.settings.CacheGet(c.Request.Context(), "export:"+token)
|
||||
if err != nil || !ok {
|
||||
httpx.Fail(c, "导出token无效或已过期")
|
||||
return
|
||||
@@ -210,7 +210,7 @@ func (h *Export) Download(expectBlank bool) gin.HandlerFunc {
|
||||
httpx.Fail(c, "token类型错误")
|
||||
return
|
||||
}
|
||||
_ = h.system.CacheDelete(c.Request.Context(), "export:"+token)
|
||||
_ = h.settings.CacheDelete(c.Request.Context(), "export:"+token)
|
||||
var data []byte
|
||||
var name string
|
||||
if expectBlank {
|
||||
|
||||
@@ -8,9 +8,9 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type Navigation struct{ service *service.SystemService }
|
||||
type Navigation struct{ service *service.UserService }
|
||||
|
||||
func NewNavigation(service *service.SystemService) *Navigation { return &Navigation{service: service} }
|
||||
func NewNavigation(service *service.UserService) *Navigation { return &Navigation{service: service} }
|
||||
func (h *Navigation) Menu(c *gin.Context) {
|
||||
claims := middleware.Claims(c)
|
||||
if claims == nil {
|
||||
|
||||
@@ -19,7 +19,8 @@ import (
|
||||
)
|
||||
|
||||
type Public struct {
|
||||
system *service.SystemService
|
||||
auth *service.AuthService
|
||||
system *service.SystemConfigService
|
||||
settings *service.SettingsService
|
||||
audit *service.AuditService
|
||||
scheduler *worker.TaskScheduler
|
||||
@@ -27,8 +28,8 @@ type Public struct {
|
||||
store *captchaStore
|
||||
}
|
||||
|
||||
func NewPublic(runtime *conf.Runtime, system *service.SystemService, settings *service.SettingsService, audit *service.AuditService, scheduler *worker.TaskScheduler) *Public {
|
||||
return &Public{system: system, settings: settings, audit: audit, scheduler: scheduler, runtime: runtime, store: &captchaStore{service: system, runtime: runtime}}
|
||||
func NewPublic(runtime *conf.Runtime, auth *service.AuthService, system *service.SystemConfigService, settings *service.SettingsService, audit *service.AuditService, scheduler *worker.TaskScheduler) *Public {
|
||||
return &Public{auth: auth, system: system, settings: settings, audit: audit, scheduler: scheduler, runtime: runtime, store: &captchaStore{service: settings, runtime: runtime}}
|
||||
}
|
||||
|
||||
func (h *Public) captchaConfig() (int, int, int) {
|
||||
@@ -55,7 +56,7 @@ func (h *Public) Captcha(c *gin.Context) {
|
||||
if security != nil {
|
||||
keyLong, width, height = security.KeyLong, security.ImgWidth, security.ImgHeight
|
||||
ttl := time.Duration(security.CaptchaTimeout) * time.Second
|
||||
failures, _ := ensureLoginIPCounter(c.Request.Context(), h.system, c.ClientIP(), ttl)
|
||||
failures, _ := ensureLoginIPCounter(c.Request.Context(), h.settings, c.ClientIP(), ttl)
|
||||
openCaptcha = security.CaptchaOpen == 0 || failures > security.CaptchaOpen
|
||||
}
|
||||
driver := base64Captcha.NewDriverDigit(height, width, keyLong, 0.7, 80)
|
||||
@@ -75,7 +76,7 @@ func (h *Public) Login(c *gin.Context) {
|
||||
}
|
||||
security, _ := h.settings.CurrentSecurity(c.Request.Context())
|
||||
if security != nil && security.LockEnable {
|
||||
if _, locked, _ := h.system.CacheGet(c.Request.Context(), "login:lock:"+req.Username); locked {
|
||||
if _, locked, _ := h.settings.CacheGet(c.Request.Context(), "login:lock:"+req.Username); locked {
|
||||
httpx.Fail(c, "账号已锁定,请 "+strconv.Itoa(security.LockDuration)+" 分钟后再试")
|
||||
_ = h.audit.RecordLoginRequest(c.Request.Context(), &dto.LoginLogRequest{Username: req.Username, IP: c.ClientIP(), Status: false, ErrorMessage: "账号已锁定", Agent: c.Request.UserAgent()})
|
||||
return
|
||||
@@ -87,18 +88,18 @@ func (h *Public) Login(c *gin.Context) {
|
||||
if security.CaptchaTimeout > 0 {
|
||||
ipTTL = time.Duration(security.CaptchaTimeout) * time.Second
|
||||
}
|
||||
failures, _ := ensureLoginIPCounter(c.Request.Context(), h.system, c.ClientIP(), ipTTL)
|
||||
failures, _ := ensureLoginIPCounter(c.Request.Context(), h.settings, c.ClientIP(), ipTTL)
|
||||
requireCaptcha = security.CaptchaOpen == 0 || failures > security.CaptchaOpen
|
||||
}
|
||||
if requireCaptcha && (req.CaptchaID == "" || req.Captcha == "" || !h.store.Verify(req.CaptchaID, req.Captcha, true)) {
|
||||
_, _ = h.system.CacheIncrement(c.Request.Context(), c.ClientIP(), ipTTL)
|
||||
_, _ = h.settings.CacheIncrement(c.Request.Context(), c.ClientIP(), ipTTL)
|
||||
_ = h.audit.RecordLoginRequest(c.Request.Context(), &dto.LoginLogRequest{Username: req.Username, IP: c.ClientIP(), Status: false, ErrorMessage: "验证码错误", Agent: c.Request.UserAgent()})
|
||||
httpx.Fail(c, "验证码错误")
|
||||
return
|
||||
}
|
||||
result, err := h.system.Login(c.Request.Context(), req.Username, req.Password)
|
||||
result, err := h.auth.Login(c.Request.Context(), req.Username, req.Password)
|
||||
if err != nil {
|
||||
_, _ = h.system.CacheIncrement(c.Request.Context(), c.ClientIP(), ipTTL)
|
||||
_, _ = h.settings.CacheIncrement(c.Request.Context(), c.ClientIP(), ipTTL)
|
||||
if errors.Is(err, biz.ErrUserDisabled) {
|
||||
var disabled *service.UserDisabledError
|
||||
errors.As(err, &disabled)
|
||||
@@ -113,9 +114,9 @@ func (h *Public) Login(c *gin.Context) {
|
||||
_ = h.audit.RecordLoginRequest(c.Request.Context(), &dto.LoginLogRequest{Username: req.Username, IP: c.ClientIP(), Status: false, ErrorMessage: "用户名不存在或者密码错误", Agent: c.Request.UserAgent()})
|
||||
if security != nil && security.LockEnable {
|
||||
lockTTL := time.Duration(security.LockDuration) * time.Minute
|
||||
failures, _ := h.system.CacheIncrement(c.Request.Context(), "login:fail:"+req.Username, lockTTL)
|
||||
failures, _ := h.settings.CacheIncrement(c.Request.Context(), "login:fail:"+req.Username, lockTTL)
|
||||
if int(failures) >= security.LockThreshold {
|
||||
_ = h.system.CacheSet(c.Request.Context(), "login:lock:"+req.Username, "1", lockTTL)
|
||||
_ = h.settings.CacheSet(c.Request.Context(), "login:lock:"+req.Username, "1", lockTTL)
|
||||
}
|
||||
}
|
||||
httpx.Fail(c, "用户名不存在或者密码错误")
|
||||
@@ -123,15 +124,15 @@ func (h *Public) Login(c *gin.Context) {
|
||||
}
|
||||
userID, _ := result.User["ID"].(uint)
|
||||
_ = h.audit.RecordLoginRequest(c.Request.Context(), &dto.LoginLogRequest{Username: req.Username, IP: c.ClientIP(), Status: true, Agent: c.Request.UserAgent(), UserID: userID})
|
||||
_ = h.system.CacheDelete(c.Request.Context(), "login:fail:"+req.Username)
|
||||
_ = h.system.CacheDelete(c.Request.Context(), "login:lock:"+req.Username)
|
||||
_ = h.settings.CacheDelete(c.Request.Context(), "login:fail:"+req.Username)
|
||||
_ = h.settings.CacheDelete(c.Request.Context(), "login:lock:"+req.Username)
|
||||
maxAge := int(time.Until(time.UnixMilli(result.ExpiresAt)).Seconds())
|
||||
httpx.SetTokenCookie(c, result.Token, maxAge)
|
||||
httpx.Write(c, httpx.CodeSuccess, result, "登录成功")
|
||||
}
|
||||
|
||||
func ensureLoginIPCounter(ctx context.Context, system *service.SystemService, ip string, expiration time.Duration) (int, error) {
|
||||
value, exists, err := system.CacheGet(ctx, ip)
|
||||
func ensureLoginIPCounter(ctx context.Context, settings *service.SettingsService, ip string, expiration time.Duration) (int, error) {
|
||||
value, exists, err := settings.CacheGet(ctx, ip)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@@ -141,7 +142,7 @@ func ensureLoginIPCounter(ctx context.Context, system *service.SystemService, ip
|
||||
if expiration <= 0 {
|
||||
expiration = time.Hour
|
||||
}
|
||||
if err = system.CacheSet(ctx, ip, "1", expiration); err != nil {
|
||||
if err = settings.CacheSet(ctx, ip, "1", expiration); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return 1, nil
|
||||
@@ -194,7 +195,7 @@ func (h *Public) InitializeDatabase(engine *gin.Engine) gin.HandlerFunc {
|
||||
}
|
||||
|
||||
type captchaStore struct {
|
||||
service *service.SystemService
|
||||
service *service.SettingsService
|
||||
runtime *conf.Runtime
|
||||
}
|
||||
|
||||
|
||||
@@ -16,12 +16,12 @@ import (
|
||||
)
|
||||
|
||||
type SystemConfig struct {
|
||||
system *service.SystemService
|
||||
system *service.SystemConfigService
|
||||
settings *service.SettingsService
|
||||
scheduler *worker.TaskScheduler
|
||||
}
|
||||
|
||||
func NewSystemConfig(system *service.SystemService, settings *service.SettingsService, scheduler *worker.TaskScheduler) *SystemConfig {
|
||||
func NewSystemConfig(system *service.SystemConfigService, settings *service.SettingsService, scheduler *worker.TaskScheduler) *SystemConfig {
|
||||
return &SystemConfig{system: system, settings: settings, scheduler: scheduler}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,9 +12,14 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type User struct{ service *service.SystemService }
|
||||
type User struct {
|
||||
service *service.UserService
|
||||
auth *service.AuthService
|
||||
}
|
||||
|
||||
func NewUser(service *service.SystemService) *User { return &User{service: service} }
|
||||
func NewUser(user *service.UserService, auth *service.AuthService) *User {
|
||||
return &User{service: user, auth: auth}
|
||||
}
|
||||
|
||||
func (h *User) List(c *gin.Context) {
|
||||
var req dto.UserListRequest
|
||||
@@ -155,7 +160,7 @@ func (h *User) SwitchAuthority(c *gin.Context) {
|
||||
httpx.Fail(c, "参数错误")
|
||||
return
|
||||
}
|
||||
login, err := h.service.SwitchAuthority(c.Request.Context(), claims.ID, req.AuthorityID)
|
||||
login, err := h.auth.SwitchAuthority(c.Request.Context(), claims.ID, req.AuthorityID)
|
||||
if err != nil {
|
||||
httpx.Fail(c, err.Error())
|
||||
return
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func SecurityRateLimit(system *service.SystemService, settings *service.SettingsService) gin.HandlerFunc {
|
||||
func SecurityRateLimit(settings *service.SettingsService) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
path := strings.TrimSuffix(c.Request.URL.Path, "/")
|
||||
if !strings.HasSuffix(path, "/base/login") && !strings.HasSuffix(path, "/base/captcha") {
|
||||
@@ -27,7 +27,7 @@ func SecurityRateLimit(system *service.SystemService, settings *service.Settings
|
||||
window = 60
|
||||
}
|
||||
key := "KRA_SecLimit" + c.ClientIP() + c.FullPath()
|
||||
count, cacheErr := system.CacheIncrement(c.Request.Context(), key, time.Duration(window)*time.Second)
|
||||
count, cacheErr := settings.CacheIncrement(c.Request.Context(), key, time.Duration(window)*time.Second)
|
||||
if cacheErr == nil && int(count) > config.LimitCount {
|
||||
httpx.Fail(c, "请求太过频繁,请稍后再试")
|
||||
c.Abort()
|
||||
|
||||
@@ -8,4 +8,4 @@ import (
|
||||
)
|
||||
|
||||
// ProviderSet is server providers.
|
||||
var ProviderSet = wire.NewSet(NewGinEngine, NewGinServer, handler.NewAuthority, handler.NewMenu, handler.NewAPI, handler.NewPermission, handler.NewOrganization, handler.NewAnnouncement, handler.NewEmail, handler.NewTask, handler.NewMedia, handler.NewAudit, handler.NewExport, handler.NewVersion, handler.NewDictionary, handler.NewParameter, handler.NewAPIToken, handler.NewSystemConfig, handler.NewPublic, handler.NewUser, handler.NewNavigation, handler.NewSession, worker.NewTaskScheduler)
|
||||
var ProviderSet = wire.NewSet(NewGinEngine, NewGinServer, handler.NewAuthority, handler.NewMenu, handler.NewAPI, handler.NewPermission, handler.NewOrganization, handler.NewAnnouncement, handler.NewEmail, handler.NewTask, handler.NewMedia, handler.NewAudit, handler.NewExport, handler.NewVersion, handler.NewDictionary, handler.NewParameter, handler.NewAPIToken, handler.NewSystemConfig, handler.NewPublic, handler.NewUser, handler.NewNavigation, handler.NewSession, worker.NewTaskExecutor, worker.NewTaskScheduler)
|
||||
|
||||
Reference in New Issue
Block a user