75 lines
2.1 KiB
Go
75 lines
2.1 KiB
Go
package auth
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"github.com/gofiber/fiber/v2"
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
|
"github.com/techxcar/backend/pkg/database"
|
|
)
|
|
|
|
func RequireAuth(secret string) fiber.Handler {
|
|
return func(c *fiber.Ctx) error {
|
|
authHeader := c.Get("Authorization")
|
|
if authHeader == "" {
|
|
return fiber.NewError(401, "autenticação necessária")
|
|
}
|
|
parts := strings.SplitN(authHeader, " ", 2)
|
|
if len(parts) != 2 || parts[0] != "Bearer" {
|
|
return fiber.NewError(401, "formato de autorização inválido")
|
|
}
|
|
claims, err := ValidateToken(parts[1], secret)
|
|
if err != nil {
|
|
return fiber.NewError(401, "token inválido ou expirado")
|
|
}
|
|
c.Locals("claims", claims)
|
|
return c.Next()
|
|
}
|
|
}
|
|
|
|
func RequireRole(roles ...string) fiber.Handler {
|
|
return func(c *fiber.Ctx) error {
|
|
claims, ok := c.Locals("claims").(*Claims)
|
|
if !ok {
|
|
return fiber.NewError(401, "autenticação necessária")
|
|
}
|
|
for _, role := range roles {
|
|
if claims.Role == role {
|
|
return c.Next()
|
|
}
|
|
}
|
|
return fiber.NewError(403, "acesso não autorizado")
|
|
}
|
|
}
|
|
|
|
// TenantMiddleware acquires a dedicated pgxpool connection per request,
|
|
// sets the tenant search_path, stores the connection in c.Locals("conn"),
|
|
// and releases the connection after the handler chain completes.
|
|
func TenantMiddleware(db *database.DB) fiber.Handler {
|
|
return func(c *fiber.Ctx) error {
|
|
claims, ok := c.Locals("claims").(*Claims)
|
|
if !ok || claims.TenantID == "" {
|
|
return c.Next()
|
|
}
|
|
conn, err := db.Pool.Acquire(c.Context())
|
|
if err != nil {
|
|
return fiber.NewError(500, "erro interno ao adquirir conexão")
|
|
}
|
|
schema := `"tenant_` + strings.ReplaceAll(claims.TenantID, "-", "_") + `"`
|
|
if _, err := conn.Exec(c.Context(), "SET search_path = "+schema+", public"); err != nil {
|
|
conn.Release()
|
|
return fiber.NewError(500, "erro interno ao definir schema")
|
|
}
|
|
c.Locals("conn", conn)
|
|
err = c.Next()
|
|
conn.Release()
|
|
return err
|
|
}
|
|
}
|
|
|
|
// GetConn returns the tenant-scoped connection stored by TenantMiddleware.
|
|
func GetConn(c *fiber.Ctx) *pgxpool.Conn {
|
|
conn, _ := c.Locals("conn").(*pgxpool.Conn)
|
|
return conn
|
|
}
|