Fix setup issue with chi router

This commit is contained in:
2026-02-07 18:02:48 +01:00
parent f6aa40d927
commit 2b395a94e6
2 changed files with 53 additions and 48 deletions

View File

@@ -106,6 +106,27 @@ func (s *Server) init() error {
authHandle := auth.GetAuthInstance() authHandle := auth.GetAuthInstance()
// Middleware must be defined before routes in chi
s.router.Use(func(next http.Handler) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
start := time.Now()
ww := middleware.NewWrapResponseWriter(rw, r.ProtoMajor)
next.ServeHTTP(ww, r)
cclog.Debugf("%s %s (%d, %.02fkb, %dms)",
r.Method, r.URL.RequestURI(),
ww.Status(), float32(ww.BytesWritten())/1024,
time.Since(start).Milliseconds())
})
})
s.router.Use(middleware.Compress(5))
s.router.Use(middleware.Recoverer)
s.router.Use(cors.Handler(cors.Options{
AllowCredentials: true,
AllowedHeaders: []string{"X-Requested-With", "Content-Type", "Authorization", "Origin"},
AllowedMethods: []string{"GET", "POST", "HEAD", "OPTIONS"},
AllowedOrigins: []string{"*"},
}))
s.restAPIHandle = api.New() s.restAPIHandle = api.New()
info := map[string]any{} info := map[string]any{}
@@ -198,7 +219,9 @@ func (s *Server) init() error {
}) })
// API routes (JWT token auth) // API routes (JWT token auth)
s.router.Route("/api", func(securedapi chi.Router) { s.router.Route("/api", func(apiRouter chi.Router) {
// Main API routes with API auth
apiRouter.Group(func(securedapi chi.Router) {
if !config.Keys.DisableAuthentication { if !config.Keys.DisableAuthentication {
securedapi.Use(func(next http.Handler) http.Handler { securedapi.Use(func(next http.Handler) http.Handler {
return authHandle.AuthAPI(next, onFailureResponse) return authHandle.AuthAPI(next, onFailureResponse)
@@ -207,6 +230,17 @@ func (s *Server) init() error {
s.restAPIHandle.MountAPIRoutes(securedapi) s.restAPIHandle.MountAPIRoutes(securedapi)
}) })
// Metric store API routes with separate auth
apiRouter.Group(func(metricstoreapi chi.Router) {
if !config.Keys.DisableAuthentication {
metricstoreapi.Use(func(next http.Handler) http.Handler {
return authHandle.AuthMetricStoreAPI(next, onFailureResponse)
})
}
s.restAPIHandle.MountMetricStoreAPIRoutes(metricstoreapi)
})
})
// User API routes // User API routes
s.router.Route("/userapi", func(userapi chi.Router) { s.router.Route("/userapi", func(userapi chi.Router) {
if !config.Keys.DisableAuthentication { if !config.Keys.DisableAuthentication {
@@ -217,8 +251,9 @@ func (s *Server) init() error {
s.restAPIHandle.MountUserAPIRoutes(userapi) s.restAPIHandle.MountUserAPIRoutes(userapi)
}) })
// Config API routes // Config API routes (uses Group with full paths to avoid shadowing
s.router.Route("/config", func(configapi chi.Router) { // the /config page route that is registered in the secured group)
s.router.Group(func(configapi chi.Router) {
if !config.Keys.DisableAuthentication { if !config.Keys.DisableAuthentication {
configapi.Use(func(next http.Handler) http.Handler { configapi.Use(func(next http.Handler) http.Handler {
return authHandle.AuthConfigAPI(next, onFailureResponse) return authHandle.AuthConfigAPI(next, onFailureResponse)
@@ -244,16 +279,6 @@ func (s *Server) init() error {
} }
} }
// Metric store API routes (mounted under /api but with different auth)
s.router.Route("/api", func(metricstoreapi chi.Router) {
if !config.Keys.DisableAuthentication {
metricstoreapi.Use(func(next http.Handler) http.Handler {
return authHandle.AuthMetricStoreAPI(next, onFailureResponse)
})
}
s.restAPIHandle.MountMetricStoreAPIRoutes(metricstoreapi)
})
// Custom 404 handler for unmatched routes // Custom 404 handler for unmatched routes
s.router.NotFound(func(rw http.ResponseWriter, r *http.Request) { s.router.NotFound(func(rw http.ResponseWriter, r *http.Request) {
if strings.HasPrefix(r.URL.Path, "/api/") || strings.HasPrefix(r.URL.Path, "/userapi/") || if strings.HasPrefix(r.URL.Path, "/api/") || strings.HasPrefix(r.URL.Path, "/userapi/") ||
@@ -287,15 +312,6 @@ func (s *Server) init() error {
s.router.Handle("/*", http.FileServer(http.Dir(config.Keys.StaticFiles))) s.router.Handle("/*", http.FileServer(http.Dir(config.Keys.StaticFiles)))
} }
s.router.Use(middleware.Compress(5))
s.router.Use(middleware.Recoverer)
s.router.Use(cors.Handler(cors.Options{
AllowCredentials: true,
AllowedHeaders: []string{"X-Requested-With", "Content-Type", "Authorization", "Origin"},
AllowedMethods: []string{"GET", "POST", "HEAD", "OPTIONS"},
AllowedOrigins: []string{"*"},
}))
return nil return nil
} }
@@ -306,19 +322,6 @@ const (
) )
func (s *Server) Start(ctx context.Context) error { func (s *Server) Start(ctx context.Context) error {
// Add request logging middleware
s.router.Use(func(next http.Handler) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
start := time.Now()
ww := middleware.NewWrapResponseWriter(rw, r.ProtoMajor)
next.ServeHTTP(ww, r)
cclog.Debugf("%s %s (%d, %.02fkb, %dms)",
r.Method, r.URL.RequestURI(),
ww.Status(), float32(ww.BytesWritten())/1024,
time.Since(start).Milliseconds())
})
})
// Use configurable timeouts with defaults // Use configurable timeouts with defaults
readTimeout := time.Duration(defaultReadTimeout) * time.Second readTimeout := time.Duration(defaultReadTimeout) * time.Second
writeTimeout := time.Duration(defaultWriteTimeout) * time.Second writeTimeout := time.Duration(defaultWriteTimeout) * time.Second

View File

@@ -140,16 +140,18 @@ func (api *RestAPI) MountMetricStoreAPIRoutes(r chi.Router) {
// MountConfigAPIRoutes registers configuration and user management endpoints. // MountConfigAPIRoutes registers configuration and user management endpoints.
// These routes use session-based authentication and require admin privileges. // These routes use session-based authentication and require admin privileges.
// Routes use full paths (including /config prefix) to avoid conflicting with
// the /config page route when registered via Group instead of Route.
func (api *RestAPI) MountConfigAPIRoutes(r chi.Router) { func (api *RestAPI) MountConfigAPIRoutes(r chi.Router) {
// Settings Frontend Uses SessionAuth // Settings Frontend Uses SessionAuth
if api.Authentication != nil { if api.Authentication != nil {
r.Get("/roles/", api.getRoles) r.Get("/config/roles/", api.getRoles)
r.Post("/users/", api.createUser) r.Post("/config/users/", api.createUser)
r.Put("/users/", api.createUser) r.Put("/config/users/", api.createUser)
r.Get("/users/", api.getUsers) r.Get("/config/users/", api.getUsers)
r.Delete("/users/", api.deleteUser) r.Delete("/config/users/", api.deleteUser)
r.Post("/user/{id}", api.updateUser) r.Post("/config/user/{id}", api.updateUser)
r.Post("/notice/", api.editNotice) r.Post("/config/notice/", api.editNotice)
} }
} }