Какие основные подходы к реализации аутентификации и авторизации существуют в Go?

Ответ

В Go, как и в других языках для бэкенда, важно различать два понятия:

  • Аутентификация (Authentication, AuthN) — это процесс проверки личности пользователя. Ответ на вопрос: «Кто вы?».
  • Авторизация (Authorization, AuthZ) — это процесс проверки прав доступа пользователя к определенным ресурсам. Ответ на вопрос: «Что вам разрешено делать?».

Существует два основных подхода к их реализации:

1. Token-based (на основе токенов)

Это самый популярный stateless-подход для современных API и микросервисов. Наиболее распространенный стандарт — JWT (JSON Web Token).

Процесс:

  1. Пользователь отправляет логин и пароль.
  2. Сервер проверяет их, и в случае успеха генерирует JWT, подписывая его секретным ключом.
  3. Токен возвращается клиенту, который сохраняет его (например, в localStorage или cookie).
  4. При каждом последующем запросе к защищенным ресурсам клиент отправляет этот токен в заголовке Authorization: Bearer <token>.
  5. Сервер проверяет подпись и срок действия токена. Если все в порядке, он извлекает из токена информацию о пользователе (ID, роли) и предоставляет доступ.

Пример с использованием github.com/golang-jwt/jwt/v5 (актуальная библиотека):

import (
    "time"
    "github.com/golang-jwt/jwt/v5"
)

var jwtKey = []byte("your_secret_key")

type Claims struct {
    UserID int64 `json:"user_id"`
    jwt.RegisteredClaims
}

// Генерация токена
func generateJWT(userID int64) (string, error) {
    expirationTime := time.Now().Add(24 * time.Hour)
    claims := &Claims{
        UserID: userID,
        RegisteredClaims: jwt.RegisteredClaims{
            ExpiresAt: jwt.NewNumericDate(expirationTime),
        },
    }

    token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
    return token.SignedString(jwtKey)
}

// Валидация токена
func validateJWT(tokenStr string) (*Claims, error) {
    claims := &Claims{}
    token, err := jwt.ParseWithClaims(tokenStr, claims, func(token *jwt.Token) (interface{}, error) {
        return jwtKey, nil
    })

    if err != nil {
        return nil, err
    }

    if !token.Valid {
        return nil, errors.New("invalid token")
    }

    return claims, nil
}

2. Session-based (на основе сессий)

Это классический stateful-подход, часто используемый в монолитных веб-приложениях.

Процесс:

  1. Пользователь отправляет логин и пароль.
  2. Сервер проверяет их и создает сессию, сохраняя ее ID и данные пользователя у себя (в памяти, Redis, базе данных).
  3. Клиенту в cookie отправляется только идентификатор сессии.
  4. При каждом запросе браузер автоматически отправляет cookie с ID сессии.
  5. Сервер находит сессию по ID и получает данные пользователя.

Для этого подхода в Go часто используется пакет gorilla/sessions.

В современных веб-фреймворках (Gin, Echo, Chi) проверка токенов или сессий обычно выносится в middleware, который защищает определенные эндпоинты.