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. - Тип значения в Locals —
c.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 и опирается на реальные контракты официальной документации.