OAuth 2.0 и JWT авторизация на Go: полное руководство для начинающих

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение: зачем нужны OAuth 2.0 и JWT в Go?

Современная веб-разработка немыслима без безопасной аутентификации и авторизации. Если вы пишете на Go (Golang) свой первый API, микросервис или веб-приложение, рано или поздно вы столкнетесь с необходимостью защитить данные пользователей. Два стандарта — OAuth 2.0 и JWT (JSON Web Token) — стали золотым стандартом в этой области.

В этой статье мы разберем, как работают OAuth 2.0 и JWT, и напишем простую, но рабочую реализацию на Go. Вы узнаете, как выдавать токены доступа, проверять их и защищать свои эндпоинты. Статья ориентирована на начинающих разработчиков, знакомых с основами Go и HTTP.

Что такое OAuth 2.0 и JWT? Простыми словами

OAuth 2.0 — протокол делегированного доступа

OAuth 2.0 — это не библиотека и не функция, а протокол. Представьте, что вы хотите войти на сайт через Google. OAuth 2.0 позволяет сайту получить от Google ограниченный доступ к вашим данным (например, email) без того, чтобы вы передавали ему свой пароль от Google. Это называется "делегированный доступ".

Основные роли в OAuth 2.0:

  • Resource Owner — пользователь (вы).
  • Client — приложение, которое хочет получить доступ (наш сайт).
  • Authorization Server — сервер, который выдает токены (Google).
  • Resource Server — сервер с данными пользователя (API Google).

JWT — формат токена

JWT (JSON Web Token) — это компактный и самодостаточный способ передачи информации между сторонами в виде JSON-объекта. Он состоит из трех частей, разделенных точками:

  • Header — тип токена и алгоритм подписи (например, HS256).
  • Payload — данные (claims): ID пользователя, роль, срок действия.
  • Signature — подпись, которая гарантирует, что токен не был изменен.

JWT часто используется как Access Token в OAuth 2.0. Сервер подписывает токен секретным ключом, а клиент отправляет его в заголовке Authorization: Bearer <token>.

Практика: реализация JWT авторизации на Go

Мы напишем небольшой HTTP-сервер на Go, который будет выдавать JWT токены и проверять их на защищенных маршрутах. Для работы с JWT мы используем популярную библиотеку github.com/golang-jwt/jwt/v5.

Шаг 1: Установка зависимостей и структура проекта

Создайте новый модуль и установите библиотеку:

go mod init auth-example
go get github.com/golang-jwt/jwt/v5
go get golang.org/x/crypto

Структура файлов будет простой:

  • main.go — точка входа и маршруты.
  • auth.go — логика создания и проверки JWT.
  • handlers.go — обработчики HTTP.

Шаг 2: Создание JWT токена

Создадим файл auth.go. Здесь мы определим секретный ключ (в реальном проекте храните его в .env) и функцию для генерации токена.

package main

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

var jwtSecret = []byte("your-secret-key-here")

type Claims struct {
    UserID   int    `json:"user_id"`
    Username string `json:"username"`
    jwt.RegisteredClaims
}

func GenerateToken(userID int, username string) (string, error) {
    claims := Claims{
        UserID:   userID,
        Username: username,
        RegisteredClaims: jwt.RegisteredClaims{
            ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)),
            IssuedAt:  jwt.NewNumericDate(time.Now()),
            Issuer:    "auth-example",
        },
    }

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

Шаг 3: Проверка и парсинг JWT токена

Добавим в auth.go функцию для валидации токена из HTTP-запроса:

func ValidateToken(tokenString string) (*Claims, error) {
    token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) {
        if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
            return nil, jwt.ErrSignatureInvalid
        }
        return jwtSecret, nil
    })

    if err != nil {
        return nil, err
    }

    claims, ok := token.Claims.(*Claims)
    if !ok || !token.Valid {
        return nil, jwt.ErrTokenInvalid
    }

    return claims, nil
}

Шаг 4: HTTP обработчики и middleware

В handlers.go создадим простой обработчик входа (логин) и защищенный маршрут. Также напишем middleware для проверки JWT.

package main

import (
    "encoding/json"
    "net/http"
    "strings"
)

// Структура для ответа
type TokenResponse struct {
    Token string `json:"token"`
}

// Обработчик логина (имитация)
func LoginHandler(w http.ResponseWriter, r *http.Request) {
    if r.Method != http.MethodPost {
        http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
        return
    }

    // В реальном проекте здесь проверка логина/пароля из БД
    // Сейчас просто генерируем токен для пользователя с ID=1
    token, err := GenerateToken(1, "john_doe")
    if err != nil {
        http.Error(w, "Failed to generate token", http.StatusInternalServerError)
        return
    }

    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(TokenResponse{Token: token})
}

// Middleware для проверки JWT
func AuthMiddleware(next http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        authHeader := r.Header.Get("Authorization")
        if authHeader == "" {
            http.Error(w, "Missing authorization header", http.StatusUnauthorized)
            return
        }

        // Ожидаем формат "Bearer <token>"
        parts := strings.Split(authHeader, " ")
        if len(parts) != 2 || parts                

Блоги

Рекомендаций по книгам