Авторизация и аутентификация в Go: пакеты и практические примеры

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

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

Начать курс

Авторизация и аутентификация в Go (Golang): обзор ключевых инструментов

Аутентификация (проверка подлинности пользователя) и авторизация (проверка прав доступа) — фундаментальные компоненты любого веб-приложения. В экосистеме Go (Golang) существует несколько проверенных библиотек, которые позволяют реализовать эти механизмы быстро, безопасно и с минимальным количеством кода. В этой статье мы рассмотрим четыре основных подхода: хеширование паролей, JWT-токены, управление сессиями и OAuth2.

1. Хеширование паролей: golang.org/x/crypto/bcrypt

Первый шаг любой аутентификации — безопасное хранение паролей. Никогда не храните пароли в открытом виде! Пакет bcrypt из стандартной коллекции Go предоставляет проверенный алгоритм хеширования с адаптивной стоимостью (cost factor).

Установка:

go get golang.org/x/crypto/bcrypt

Пример регистрации и входа:

package main

import (
    "fmt"
    "golang.org/x/crypto/bcrypt"
)

func hashPassword(password string) (string, error) {
    bytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
    return string(bytes), err
}

func checkPasswordHash(password, hash string) bool {
    err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
    return err == nil
}

func main() {
    password := "mySecretP@ssw0rd"
    hash, _ := hashPassword(password)

    fmt.Println("Hash:", hash)

    // Проверка правильного пароля
    match := checkPasswordHash(password, hash)
    fmt.Println("Password match:", match) // true

    // Проверка неправильного пароля
    match = checkPasswordHash("wrong", hash)
    fmt.Println("Wrong password match:", match) // false
}

Важно: bcrypt.DefaultCost равен 10. Для более высокого уровня безопасности (но медленнее) используйте значение 12-14. Никогда не используйте cost меньше 10.

2. JWT (JSON Web Tokens) — github.com/golang-jwt/jwt/v5

JWT — это компактный способ передачи данных между сторонами в виде JSON-объекта. Идеально подходит для REST API и микросервисов. Пакет golang-jwt/jwt — самый популярный и активно поддерживаемый.

Установка:

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

Пример создания и проверки JWT:

package main

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

var jwtSecret = []byte("your-secret-key-keep-it-safe")

func createToken(userID string) (string, error) {
    claims := jwt.MapClaims{
        "user_id": userID,
        "exp":     time.Now().Add(24 * time.Hour).Unix(),
    }
    token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
    return token.SignedString(jwtSecret)
}

func verifyToken(tokenString string) (string, error) {
    token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
        if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
            return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
        }
        return jwtSecret, nil
    })
    if err != nil {
        return "", err
    }
    if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
        return claims["user_id"].(string), nil
    }
    return "", fmt.Errorf("invalid token")
}

func main() {
    token, _ := createToken("user123")
    fmt.Println("JWT:", token)

    userID, err := verifyToken(token)
    if err != nil {
        fmt.Println("Error:", err)
    } else {
        fmt.Println("Authenticated user:", userID)
    }
}

Совет: Храните секретный ключ в переменных окружения, а не в коде. Для продакшена используйте асимметричное шифрование (RS256).

3. Управление сессиями — gorilla/sessions

Для классических веб-приложений с HTML-шаблонами часто удобнее использовать серверные сессии. Пакет gorilla/sessions предоставляет готовый механизм для работы с cookie-сессиями.

Установка:

go get github.com/gorilla/sessions

Пример с использованием HTTP-сервера:

package main

import (
    "fmt"
    "net/http"
    "github.com/gorilla/sessions"
)

var store = sessions.NewCookieStore([]byte("super-secret-key-32-bytes-long!"))

func loginHandler(w http.ResponseWriter, r *http.Request) {
    session, _ := store.Get(r, "session-name")
    session.Values["authenticated"] = true
    session.Values["username"] = r.FormValue("username")
    session.Save(r, w)
    fmt.Fprintf(w, "Logged in                    

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