first commit
This commit is contained in:
108
middlewares/auth_middleware.go
Normal file
108
middlewares/auth_middleware.go
Normal file
@@ -0,0 +1,108 @@
|
||||
package middlewares
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"ares/services"
|
||||
|
||||
"github.com/gofiber/fiber/v3"
|
||||
)
|
||||
|
||||
const authClaimsKey = "auth_claims"
|
||||
|
||||
func RequireAuth(c fiber.Ctx) error {
|
||||
// First try Authorization header (Bearer JWT)
|
||||
authHeader := strings.TrimSpace(c.Get("Authorization"))
|
||||
if authHeader != "" {
|
||||
parts := strings.SplitN(authHeader, " ", 2)
|
||||
if len(parts) != 2 || !strings.EqualFold(parts[0], "Bearer") || strings.TrimSpace(parts[1]) == "" {
|
||||
// If request originates from browser/HTMX, redirect to login instead of returning JSON
|
||||
if c.Get("HX-Request") == "true" {
|
||||
c.Set("HX-Redirect", "/login")
|
||||
return c.SendStatus(fiber.StatusOK)
|
||||
}
|
||||
accept := strings.ToLower(c.Get("Accept"))
|
||||
if strings.Contains(accept, "text/html") || strings.HasPrefix(c.Path(), "/admin") {
|
||||
return c.Redirect().To("/login")
|
||||
}
|
||||
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "invalid authorization format, expected: Bearer <token>"})
|
||||
}
|
||||
jwtService := services.NewJWTService()
|
||||
claims, err := jwtService.ValidateToken(strings.TrimSpace(parts[1]))
|
||||
if err != nil {
|
||||
if c.Get("HX-Request") == "true" {
|
||||
c.Set("HX-Redirect", "/login")
|
||||
return c.SendStatus(fiber.StatusOK)
|
||||
}
|
||||
accept := strings.ToLower(c.Get("Accept"))
|
||||
if strings.Contains(accept, "text/html") || strings.HasPrefix(c.Path(), "/admin") {
|
||||
return c.Redirect().To("/login")
|
||||
}
|
||||
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "invalid token"})
|
||||
}
|
||||
if claims.TokenType != services.TokenTypeAccess {
|
||||
if c.Get("HX-Request") == "true" {
|
||||
c.Set("HX-Redirect", "/login")
|
||||
return c.SendStatus(fiber.StatusOK)
|
||||
}
|
||||
accept := strings.ToLower(c.Get("Accept"))
|
||||
if strings.Contains(accept, "text/html") || strings.HasPrefix(c.Path(), "/admin") {
|
||||
return c.Redirect().To("/login")
|
||||
}
|
||||
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "access token required"})
|
||||
}
|
||||
c.Locals(authClaimsKey, claims)
|
||||
return c.Next()
|
||||
}
|
||||
|
||||
// Fallback: check cookie-based admin session (browser login) — expect signed JWT
|
||||
cookie := c.Cookies("admin_session")
|
||||
if cookie != "" {
|
||||
jwtService := services.NewJWTService()
|
||||
if claims, err := jwtService.ValidateToken(cookie); err == nil {
|
||||
if claims.TokenType == services.TokenTypeAccess {
|
||||
c.Locals(authClaimsKey, claims)
|
||||
return c.Next()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Default unauthorized response: redirect to login for browser requests, JSON for API clients
|
||||
if c.Get("HX-Request") == "true" {
|
||||
c.Set("HX-Redirect", "/login")
|
||||
return c.SendStatus(fiber.StatusOK)
|
||||
}
|
||||
accept := strings.ToLower(c.Get("Accept"))
|
||||
if strings.Contains(accept, "text/html") || strings.HasPrefix(c.Path(), "/admin") {
|
||||
return c.Redirect().To("/login")
|
||||
}
|
||||
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "authorization header is required"})
|
||||
}
|
||||
|
||||
func RequireAdmin(c fiber.Ctx) error {
|
||||
claims, ok := GetAuthClaims(c)
|
||||
if !ok {
|
||||
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "unauthorized"})
|
||||
}
|
||||
if !claims.IsAdmin {
|
||||
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{"error": "admin role required"})
|
||||
}
|
||||
return c.Next()
|
||||
}
|
||||
|
||||
func RequireNormalUser(c fiber.Ctx) error {
|
||||
claims, ok := GetAuthClaims(c)
|
||||
if !ok {
|
||||
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "unauthorized"})
|
||||
}
|
||||
if claims.IsAdmin {
|
||||
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{"error": "only normal users can access this endpoint"})
|
||||
}
|
||||
return c.Next()
|
||||
}
|
||||
|
||||
func GetAuthClaims(c fiber.Ctx) (*services.JWTClaim, bool) {
|
||||
raw := c.Locals(authClaimsKey)
|
||||
claims, ok := raw.(*services.JWTClaim)
|
||||
return claims, ok
|
||||
}
|
||||
Reference in New Issue
Block a user