refactor: split backend transport and domain modules
This commit is contained in:
+17
-87
@@ -13,11 +13,14 @@ import (
|
||||
|
||||
"kra/internal/biz"
|
||||
"kra/internal/conf"
|
||||
"kra/internal/server/handler"
|
||||
servermiddleware "kra/internal/server/middleware"
|
||||
serverrouter "kra/internal/server/router"
|
||||
"kra/internal/service"
|
||||
"kra/internal/worker"
|
||||
"kra/pkg/adminauth"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
"github.com/mojocn/base64Captcha"
|
||||
)
|
||||
|
||||
@@ -30,10 +33,10 @@ type GinServer struct {
|
||||
logger *slog.Logger
|
||||
}
|
||||
|
||||
func NewGinServer(c *conf.Server, config *conf.AdminBackend, svc *service.SystemService, access *service.AccessService, settings *service.SettingsService, versions *service.VersionService, exports *service.ExportService, audit *service.AuditService, tasks *service.TaskService, media *service.MediaService, announcements *service.AnnouncementService, emails *service.EmailService, scheduler *TaskScheduler, logger *slog.Logger) *GinServer {
|
||||
func NewGinServer(c *conf.Server, config *conf.AdminBackend, svc *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, settings *service.SettingsService, versions *service.VersionService, exports *service.ExportService, audit *service.AuditService, media *service.MediaService, emails *service.EmailService, scheduler *worker.TaskScheduler, logger *slog.Logger) *GinServer {
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
engine := gin.New()
|
||||
engine.Use(ginRequestMeta(), emailErrorAlert(emails, logger), gin.Recovery(), securityRateLimit(svc, settings), operationAudit(audit))
|
||||
engine.Use(servermiddleware.RequestMeta(), emailErrorAlert(emails, logger), gin.Recovery(), securityRateLimit(svc, settings), operationAudit(audit))
|
||||
prefix := ""
|
||||
if config != nil {
|
||||
prefix = strings.TrimSuffix(config.RouterPrefix, "/")
|
||||
@@ -44,18 +47,22 @@ func NewGinServer(c *conf.Server, config *conf.AdminBackend, svc *service.System
|
||||
})
|
||||
registerPublicRoutes(public, engine, config, svc, settings, access, audit, scheduler)
|
||||
private := engine.Group(prefix)
|
||||
private.Use(jwtAuth(config, settings), mustChangePasswordGuard(), accessControl(access, audit))
|
||||
private.Use(servermiddleware.Auth(config, settings), servermiddleware.MustChangePassword(), servermiddleware.AccessControl(access, audit))
|
||||
registerPrivateRoutes(private, svc, settings)
|
||||
registerAccessRoutes(private, engine, access)
|
||||
serverrouter.RegisterAuthority(private, authority)
|
||||
serverrouter.RegisterMenu(private, menu)
|
||||
serverrouter.RegisterAPI(private, engine, api)
|
||||
serverrouter.RegisterPermission(private, permission)
|
||||
serverrouter.RegisterOrganization(private, organization)
|
||||
registerSettingsRoutes(private, public, settings)
|
||||
registerSystemConfigRoutes(private, config, svc, settings, scheduler)
|
||||
registerVersionRoutes(private, versions)
|
||||
registerExportRoutes(private, public, svc, exports)
|
||||
registerAuditRoutes(private, public, audit)
|
||||
registerTaskRoutes(private, tasks, scheduler)
|
||||
serverrouter.RegisterTask(private, task)
|
||||
registerMediaRoutes(private, media)
|
||||
registerAnnouncementRoutes(private, public, announcements)
|
||||
registerEmailRoutes(private, emails)
|
||||
serverrouter.RegisterAnnouncement(private, public, announcement)
|
||||
serverrouter.RegisterEmail(private, email)
|
||||
|
||||
engine.NoRoute(func(c *gin.Context) {
|
||||
if serveLocalStorage(c, config) {
|
||||
@@ -100,74 +107,9 @@ func serveLocalStorage(c *gin.Context, config *conf.AdminBackend) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func jwtAuth(config *conf.AdminBackend, settings *service.SettingsService) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
token := c.GetHeader("x-token")
|
||||
if token == "" {
|
||||
token, _ = c.Cookie("x-token")
|
||||
}
|
||||
secret := ""
|
||||
if config != nil && config.Jwt != nil {
|
||||
secret = config.Jwt.SigningKey
|
||||
}
|
||||
claims, err := adminauth.Parse(token, secret)
|
||||
if err != nil {
|
||||
noAuth(c, "未登录或非法访问")
|
||||
return
|
||||
}
|
||||
if disabled, checkErr := settings.IsTokenDisabled(c.Request.Context(), token); checkErr != nil || disabled {
|
||||
noAuth(c, "登录状态已失效")
|
||||
return
|
||||
}
|
||||
if claims.ExpiresAt != nil && claims.BufferTime > 0 && time.Until(claims.ExpiresAt.Time) < time.Duration(claims.BufferTime)*time.Second {
|
||||
expires, buffer := 7*24*time.Hour, time.Duration(claims.BufferTime)*time.Second
|
||||
issuer := claims.Issuer
|
||||
if config != nil && config.Jwt != nil {
|
||||
if config.Jwt.ExpiresTime != nil {
|
||||
expires = config.Jwt.ExpiresTime.AsDuration()
|
||||
}
|
||||
if config.Jwt.BufferTime != nil {
|
||||
buffer = config.Jwt.BufferTime.AsDuration()
|
||||
}
|
||||
if config.Jwt.Issuer != "" {
|
||||
issuer = config.Jwt.Issuer
|
||||
}
|
||||
}
|
||||
newToken, newClaims, refreshErr := adminauth.Generate(secret, issuer, expires, buffer, claims.ID, claims.AuthorityID, claims.UUID, claims.Username, claims.NickName, claims.MustChangePwd)
|
||||
if refreshErr == nil {
|
||||
c.Header("new-token", newToken)
|
||||
c.Header("new-expires-at", strconv.FormatInt(newClaims.ExpiresAt.Unix(), 10))
|
||||
http.SetCookie(c.Writer, &http.Cookie{Name: "x-token", Value: newToken, Path: "/", MaxAge: int(expires.Seconds()), HttpOnly: true, SameSite: http.SameSiteStrictMode})
|
||||
}
|
||||
}
|
||||
c.Set("admin_claims", claims)
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
func currentClaims(c *gin.Context) *adminauth.Claims { return servermiddleware.Claims(c) }
|
||||
|
||||
func currentClaims(c *gin.Context) *adminauth.Claims {
|
||||
claims, _ := c.Get("admin_claims")
|
||||
result, _ := claims.(*adminauth.Claims)
|
||||
return result
|
||||
}
|
||||
|
||||
func mustChangePasswordGuard() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
claims := currentClaims(c)
|
||||
if claims == nil || !claims.MustChangePwd {
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
path := strings.TrimSuffix(c.Request.URL.Path, "/")
|
||||
if strings.HasSuffix(path, "/user/changePassword") || strings.HasSuffix(path, "/user/getUserInfo") || strings.HasSuffix(path, "/jwt/jsonInBlacklist") {
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
c.AbortWithStatusJSON(http.StatusConflict, response{Code: codePasswordChangeRequired, Data: gin.H{"needChangePassword": true}, Msg: "请先修改初始密码"})
|
||||
}
|
||||
}
|
||||
|
||||
func registerPublicRoutes(group *gin.RouterGroup, engine *gin.Engine, config *conf.AdminBackend, svc *service.SystemService, settings *service.SettingsService, access *service.AccessService, audit *service.AuditService, scheduler *TaskScheduler) {
|
||||
func registerPublicRoutes(group *gin.RouterGroup, engine *gin.Engine, config *conf.AdminBackend, svc *service.SystemService, settings *service.SettingsService, access *service.AccessService, audit *service.AuditService, scheduler *worker.TaskScheduler) {
|
||||
expiration := 3 * time.Minute
|
||||
keyLong, width, height := 6, 240, 80
|
||||
if config != nil && config.Captcha != nil {
|
||||
@@ -644,15 +586,3 @@ func (s *GinServer) Stop(ctx context.Context) error {
|
||||
s.logger.InfoContext(ctx, "Gin HTTP server stopping")
|
||||
return s.server.Shutdown(ctx)
|
||||
}
|
||||
|
||||
func ginRequestMeta() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
requestID := c.GetHeader("X-Request-Id")
|
||||
if requestID == "" {
|
||||
requestID = uuid.NewString()
|
||||
}
|
||||
c.Header("X-Request-Id", requestID)
|
||||
c.Set("request_id", requestID)
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user