fix: add proper JWT user context to router middleware
Add createJWTMiddleware helper that sets database.Users object in context, matching the original main.go JWT middleware behavior. This fixes 'authentication context error' panics in handlers that call MustGetAuthenticatedUser. Changes: - Add createJWTMiddleware() in router.go - Update all route files to use the helper - Set user claims AND database.Users object in context
This commit is contained in:
@@ -1,17 +1,10 @@
|
|||||||
package router
|
package router
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/labstack/echo-jwt/v4"
|
|
||||||
)
|
|
||||||
|
|
||||||
func registerAnalyticsRoutes(cfg *Config) {
|
func registerAnalyticsRoutes(cfg *Config) {
|
||||||
e := cfg.Echo
|
e := cfg.Echo
|
||||||
|
|
||||||
// JWT middleware for protected routes
|
// JWT middleware for protected routes
|
||||||
jwtMiddleware := echojwt.WithConfig(echojwt.Config{
|
jwtMiddleware := createJWTMiddleware(cfg)
|
||||||
SigningKey: []byte(cfg.Cfg.JWTSecret),
|
|
||||||
ContextKey: "user",
|
|
||||||
})
|
|
||||||
|
|
||||||
protected := e.Group("/api", jwtMiddleware)
|
protected := e.Group("/api", jwtMiddleware)
|
||||||
|
|
||||||
|
|||||||
+2
-15
@@ -3,8 +3,6 @@ package router
|
|||||||
import (
|
import (
|
||||||
"bookhoard/internal/handlers"
|
"bookhoard/internal/handlers"
|
||||||
|
|
||||||
"github.com/golang-jwt/jwt/v5"
|
|
||||||
"github.com/labstack/echo-jwt/v4"
|
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -16,18 +14,7 @@ func registerAuthRoutes(cfg *Config, rateLimitMiddleware echo.MiddlewareFunc) {
|
|||||||
e.POST("/api/auth/login", rateLimitMiddleware(cfg.AuthHandler.Login))
|
e.POST("/api/auth/login", rateLimitMiddleware(cfg.AuthHandler.Login))
|
||||||
|
|
||||||
// JWT middleware for protected routes
|
// JWT middleware for protected routes
|
||||||
jwtMiddleware := echojwt.WithConfig(echojwt.Config{
|
jwtMiddleware := createJWTMiddleware(cfg)
|
||||||
SigningKey: []byte(cfg.Cfg.JWTSecret),
|
|
||||||
ContextKey: "user",
|
|
||||||
SuccessHandler: func(c echo.Context) {
|
|
||||||
token := c.Get("user").(*jwt.Token)
|
|
||||||
claims := token.Claims.(jwt.MapClaims)
|
|
||||||
c.Set("user_id", claims["user_id"])
|
|
||||||
c.Set("user_role", claims["user_role"])
|
|
||||||
c.Set("user_email", claims["user_email"])
|
|
||||||
c.Set("user_username", claims["user_username"])
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
// Create protected route group
|
// Create protected route group
|
||||||
protected := e.Group("/api", jwtMiddleware)
|
protected := e.Group("/api", jwtMiddleware)
|
||||||
@@ -43,7 +30,7 @@ func registerAuthRoutes(cfg *Config, rateLimitMiddleware echo.MiddlewareFunc) {
|
|||||||
e.POST("/api/auth/logout", cfg.AuthHandler.Logout)
|
e.POST("/api/auth/logout", cfg.AuthHandler.Logout)
|
||||||
|
|
||||||
// Auth update routes
|
// Auth update routes
|
||||||
authGroup := e.Group("/api/auth", jwtMiddleware)
|
authGroup := e.Group("/api/auth", createJWTMiddleware(cfg))
|
||||||
authGroup.PUT("/email", cfg.AuthHandler.UpdateEmail)
|
authGroup.PUT("/email", cfg.AuthHandler.UpdateEmail)
|
||||||
authGroup.PUT("/username", cfg.AuthHandler.UpdateUsername)
|
authGroup.PUT("/username", cfg.AuthHandler.UpdateUsername)
|
||||||
authGroup.PUT("/password", cfg.AuthHandler.UpdatePassword)
|
authGroup.PUT("/password", cfg.AuthHandler.UpdatePassword)
|
||||||
|
|||||||
@@ -1,17 +1,10 @@
|
|||||||
package router
|
package router
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/labstack/echo-jwt/v4"
|
|
||||||
)
|
|
||||||
|
|
||||||
func registerConflictRoutes(cfg *Config) {
|
func registerConflictRoutes(cfg *Config) {
|
||||||
e := cfg.Echo
|
e := cfg.Echo
|
||||||
|
|
||||||
// JWT middleware for protected routes
|
// JWT middleware for protected routes
|
||||||
jwtMiddleware := echojwt.WithConfig(echojwt.Config{
|
jwtMiddleware := createJWTMiddleware(cfg)
|
||||||
SigningKey: []byte(cfg.Cfg.JWTSecret),
|
|
||||||
ContextKey: "user",
|
|
||||||
})
|
|
||||||
|
|
||||||
protected := e.Group("/api", jwtMiddleware)
|
protected := e.Group("/api", jwtMiddleware)
|
||||||
|
|
||||||
|
|||||||
@@ -1,27 +1,10 @@
|
|||||||
package router
|
package router
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/golang-jwt/jwt/v5"
|
|
||||||
"github.com/labstack/echo-jwt/v4"
|
|
||||||
"github.com/labstack/echo/v4"
|
|
||||||
)
|
|
||||||
|
|
||||||
func registerDeviceRoutes(cfg *Config) {
|
func registerDeviceRoutes(cfg *Config) {
|
||||||
e := cfg.Echo
|
e := cfg.Echo
|
||||||
|
|
||||||
// JWT middleware
|
// JWT middleware
|
||||||
jwtMiddleware := echojwt.WithConfig(echojwt.Config{
|
jwtMiddleware := createJWTMiddleware(cfg)
|
||||||
SigningKey: []byte(cfg.Cfg.JWTSecret),
|
|
||||||
ContextKey: "user",
|
|
||||||
SuccessHandler: func(c echo.Context) {
|
|
||||||
token := c.Get("user").(*jwt.Token)
|
|
||||||
claims := token.Claims.(jwt.MapClaims)
|
|
||||||
c.Set("user_id", claims["user_id"])
|
|
||||||
c.Set("user_role", claims["user_role"])
|
|
||||||
c.Set("user_email", claims["user_email"])
|
|
||||||
c.Set("user_username", claims["user_username"])
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
// Protected routes
|
// Protected routes
|
||||||
protected := e.Group("/api", jwtMiddleware)
|
protected := e.Group("/api", jwtMiddleware)
|
||||||
|
|||||||
@@ -2,18 +2,13 @@ package router
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bookhoard/internal/handlers"
|
"bookhoard/internal/handlers"
|
||||||
|
|
||||||
"github.com/labstack/echo-jwt/v4"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func registerMediaRoutes(cfg *Config) {
|
func registerMediaRoutes(cfg *Config) {
|
||||||
e := cfg.Echo
|
e := cfg.Echo
|
||||||
|
|
||||||
// JWT middleware for protected routes
|
// JWT middleware for protected routes
|
||||||
jwtMiddleware := echojwt.WithConfig(echojwt.Config{
|
jwtMiddleware := createJWTMiddleware(cfg)
|
||||||
SigningKey: []byte(cfg.Cfg.JWTSecret),
|
|
||||||
ContextKey: "user",
|
|
||||||
})
|
|
||||||
|
|
||||||
protected := e.Group("/api", jwtMiddleware)
|
protected := e.Group("/api", jwtMiddleware)
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package router
|
package router
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/labstack/echo-jwt/v4"
|
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -9,10 +8,7 @@ func registerQueueRoutes(cfg *Config) {
|
|||||||
e := cfg.Echo
|
e := cfg.Echo
|
||||||
|
|
||||||
// JWT middleware for protected routes
|
// JWT middleware for protected routes
|
||||||
jwtMiddleware := echojwt.WithConfig(echojwt.Config{
|
jwtMiddleware := createJWTMiddleware(cfg)
|
||||||
SigningKey: []byte(cfg.Cfg.JWTSecret),
|
|
||||||
ContextKey: "user",
|
|
||||||
})
|
|
||||||
|
|
||||||
protected := e.Group("/api", jwtMiddleware)
|
protected := e.Group("/api", jwtMiddleware)
|
||||||
|
|
||||||
|
|||||||
@@ -8,9 +8,14 @@ import (
|
|||||||
ratelimit "bookhoard/internal/middleware"
|
ratelimit "bookhoard/internal/middleware"
|
||||||
"bookhoard/internal/sync"
|
"bookhoard/internal/sync"
|
||||||
"log"
|
"log"
|
||||||
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-playground/validator/v10"
|
"github.com/go-playground/validator/v10"
|
||||||
|
"github.com/golang-jwt/jwt/v5"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
"github.com/labstack/echo-jwt/v4"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
echomiddleware "github.com/labstack/echo/v4/middleware"
|
echomiddleware "github.com/labstack/echo/v4/middleware"
|
||||||
)
|
)
|
||||||
@@ -46,6 +51,37 @@ type Config struct {
|
|||||||
LoginTracker *ratelimit.LoginAttemptTracker
|
LoginTracker *ratelimit.LoginAttemptTracker
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// createJWTMiddleware creates a JWT middleware with proper user context setup
|
||||||
|
func createJWTMiddleware(cfg *Config) echo.MiddlewareFunc {
|
||||||
|
return echojwt.WithConfig(echojwt.Config{
|
||||||
|
SigningKey: []byte(cfg.Cfg.JWTSecret),
|
||||||
|
ContextKey: "user",
|
||||||
|
SuccessHandler: func(c echo.Context) {
|
||||||
|
token := c.Get("user").(*jwt.Token)
|
||||||
|
claims := token.Claims.(jwt.MapClaims)
|
||||||
|
c.Set("user_id", claims["user_id"])
|
||||||
|
c.Set("user_role", claims["user_role"])
|
||||||
|
c.Set("user_email", claims["user_email"])
|
||||||
|
c.Set("user_username", claims["user_username"])
|
||||||
|
|
||||||
|
// Parse UUID from string claims
|
||||||
|
userIDStr, _ := claims["user_id"].(string)
|
||||||
|
userUUID, err := uuid.Parse(userIDStr)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid user ID in token"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Set("user", database.Users{
|
||||||
|
ID: pgtype.UUID{Bytes: [16]byte(userUUID), Valid: true},
|
||||||
|
Email: claims["user_email"].(string),
|
||||||
|
Username: claims["user_username"].(string),
|
||||||
|
Role: claims["user_role"].(string),
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// RegisterRoutes registers all application routes
|
// RegisterRoutes registers all application routes
|
||||||
func RegisterRoutes(cfg *Config) {
|
func RegisterRoutes(cfg *Config) {
|
||||||
e := cfg.Echo
|
e := cfg.Echo
|
||||||
|
|||||||
+1
-16
@@ -2,28 +2,13 @@ package router
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bookhoard/internal/handlers"
|
"bookhoard/internal/handlers"
|
||||||
|
|
||||||
"github.com/golang-jwt/jwt/v5"
|
|
||||||
"github.com/labstack/echo-jwt/v4"
|
|
||||||
"github.com/labstack/echo/v4"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func registerSyncRoutes(cfg *Config) {
|
func registerSyncRoutes(cfg *Config) {
|
||||||
e := cfg.Echo
|
e := cfg.Echo
|
||||||
|
|
||||||
// JWT middleware for protected routes
|
// JWT middleware for protected routes
|
||||||
jwtMiddleware := echojwt.WithConfig(echojwt.Config{
|
jwtMiddleware := createJWTMiddleware(cfg)
|
||||||
SigningKey: []byte(cfg.Cfg.JWTSecret),
|
|
||||||
ContextKey: "user",
|
|
||||||
SuccessHandler: func(c echo.Context) {
|
|
||||||
token := c.Get("user").(*jwt.Token)
|
|
||||||
claims := token.Claims.(jwt.MapClaims)
|
|
||||||
c.Set("user_id", claims["user_id"])
|
|
||||||
c.Set("user_role", claims["user_role"])
|
|
||||||
c.Set("user_email", claims["user_email"])
|
|
||||||
c.Set("user_username", claims["user_username"])
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
protected := e.Group("/api", jwtMiddleware)
|
protected := e.Group("/api", jwtMiddleware)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user