FiberMiddleCoding

Как реализовать middleware аутентификации (например, JWT) в Fiber?

Используйте github.com/gofiber/contrib/jwt: зарегистрируйте jwtware.New(jwtware.Config{SigningKey: ...}) на защищённых маршрутах, а токен читайте из c.Locals("user").(*jwt.Token).

JWT-аутентификация в Fiber

Официальный contrib-пакет github.com/gofiber/contrib/jwt оборачивает библиотеку github.com/golang-jwt/jwt/v5 и предоставляет готовый middleware для проверки Bearer-токенов.

Установка зависимостей

// go get github.com/gofiber/contrib/jwt
// go get github.com/golang-jwt/jwt/v5

Полный рабочий пример

package main

import (
	"time"

	"github.com/gofiber/contrib/jwt"
	"github.com/gofiber/fiber/v2"
	gojwt "github.com/golang-jwt/jwt/v5"
)

var jwtSecret = []byte("supersecret")

type Claims struct {
	UserID uint   `json:"user_id"`
	Role   string `json:"role"`
	gojwt.RegisteredClaims
}

func main() {
	app := fiber.New()

	// Публичный маршрут — выдача токена
	app.Post("/login", loginHandler)

	// Группа защищённых маршрутов
	api := app.Group("/api", jwtware.New(jwtware.Config{
		SigningKey: jwtware.SigningKey{
			JWTAlg: jwtware.HS256,
			Key:    jwtSecret,
		},
		ErrorHandler: func(c *fiber.Ctx, err error) error {
			return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
				"error": "invalid or expired token",
			})
		},
	}))

	api.Get("/profile", profileHandler)

	app.Listen(":3000")
}

func loginHandler(c *fiber.Ctx) error {
	// Упрощённая проверка (в реальности — сравнение хэша пароля)
	body := struct {
		Username string `json:"username"`
		Password string `json:"password"`
	}{}
	if err := c.BodyParser(&body); err != nil {
		return c.Status(400).JSON(fiber.Map{"error": "bad request"})
	}

	claims := Claims{
		UserID: 42,
		Role:   "admin",
		RegisteredClaims: gojwt.RegisteredClaims{
			ExpiresAt: gojwt.NewNumericDate(time.Now().Add(24 * time.Hour)),
			IssuedAt:  gojwt.NewNumericDate(time.Now()),
		},
	}
	token := gojwt.NewWithClaims(gojwt.SigningMethodHS256, claims)
	signed, err := token.SignedString(jwtSecret)
	if err != nil {
		return c.Status(500).JSON(fiber.Map{"error": "token generation failed"})
	}
	return c.JSON(fiber.Map{"token": signed})
}

func profileHandler(c *fiber.Ctx) error {
	// Извлекаем распарсенный токен из Locals
	token := c.Locals("user").(*gojwt.Token)
	claims := token.Claims.(gojwt.MapClaims)
	return c.JSON(fiber.Map{
		"user_id": claims["user_id"],
		"role":    claims["role"],
	})
}

Кастомный тип Claims

Для строгой типизации передайте Claims через jwtware.Config.Claims:

jwtware.New(jwtware.Config{
	SigningKey: jwtware.SigningKey{Key: jwtSecret},
	Claims:     &Claims{},
})

// В хэндлере:
claims := c.Locals("user").(*gojwt.Token).Claims.(*Claims)
fmt.Println(claims.UserID, claims.Role)

RS256 (асимметричный ключ)

import "crypto/rsa"

var publicKey *rsa.PublicKey // загружен из PEM-файла

jwtware.New(jwtware.Config{
	SigningKey: jwtware.SigningKey{
		JWTAlg: jwtware.RS256,
		Key:    publicKey,
	},
})

Подводные камни

  • HS256 с коротким секретом — секрет короче 32 байт легко брутфорсится; используйте случайные 64+ байта или переходите на RS256/ES256.
  • Отсутствие проверки exp — библиотека golang-jwt/jwt/v5 проверяет exp автоматически, но если вы парсите токен вручную с ParseWithClaims и передаёте WithoutClaimsValidation, срок действия не проверяется.
  • Хранение секрета в коде — никогда не хардкодьте секрет; читайте из переменной окружения или vault.
  • Порядок middleware: CORS перед JWT — preflight OPTIONS не содержит заголовка Authorization; JWT-middleware должен стоять после CORS, иначе preflight получит 401.
  • Тип значения в Localsc.Locals("user") возвращает interface{}; приведение к неправильному типу вызовет панику; всегда проверяйте ok при type assertion.
  • Refresh-токены не включены — contrib/jwt только проверяет access-токен; логику refresh нужно реализовывать самостоятельно.
  • Ключ "user" в Locals перезаписывается — если несколько middleware пишут в c.Locals("user"), последний затрёт предыдущего; используйте уникальные ключи.
  • Утечка информации в ErrorHandler — не возвращайте текст ошибки JWT-библиотеки клиенту напрямую (может содержать внутренние детали); оборачивайте в общее сообщение.

Common mistakes

  • Давать ответ про JWT middleware в Fiber только на уровне определения, не показывая поведение в реальном приложении.
  • Игнорировать границы ответственности вокруг темы «JWT middleware в Fiber»: кто отменяет работу, кто владеет ресурсом и где формируется ответ клиенту.
  • Не связывать JWT middleware в Fiber с observability, тестированием или безопасностью, когда это влияет на продакшен-поведение.

What the interviewer is testing

  • Точно объясняет, что именно делает JWT middleware в Fiber и где это используется в Go-коде.
  • Связывает JWT middleware в Fiber с корректным lifecycle запроса, отменой, конкурентностью или конфигурацией сервера там, где это уместно.
  • Не изобретает API и опирается на реальные контракты официальной документации.

Sources

Related topics