Авторизация и аутентификация в Go (Golang): JWT, OAuth2 и сессии

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

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

Начать курс

Авторизация и аутентификация в Go (Golang)

Безопасность веб-приложений на Go начинается с правильной реализации механизмов аутентификации (проверки "кто вы") и авторизации (проверки "что вам можно делать"). В этой статье мы разберём три основных подхода: JWT (JSON Web Tokens), OAuth2 и сессионную аутентификацию. Каждый из них имеет свои сценарии использования, преимущества и недостатки.

1. Аутентификация с помощью JWT (JSON Web Token)

JWT — это компактный и самодостаточный способ передачи информации между сторонами в виде JSON-объекта. В Go для работы с JWT чаще всего используется библиотека github.com/golang-jwt/jwt/v5.

Установка:

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

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

package main

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

var jwtSecret = []byte("my_secret_key")

// Создание токена
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 validateToken(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("неверный метод подписи")
		}
		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("неверный токен")
}

func main() {
	token, _ := createToken("user123")
	fmt.Println("Токен:", token)

	userID, err := validateToken(token)
	if err != nil {
		fmt.Println("Ошибка:", err)
	} else {
		fmt.Println("Пользователь:", userID)
	}
}

2. Аутентификация через OAuth2

OAuth2 — это протокол делегированного доступа, который позволяет пользователям входить через сторонние сервисы (Google, GitHub, VK и др.). В Go популярна библиотека golang.org/x/oauth2.

Установка:

go get golang.org/x/oauth2

Пример OAuth2 с Google:

package main

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"
)

var googleOauthConfig = &oauth2.Config{
	RedirectURL:  "http://localhost:8080/callback",
	ClientID:     "your-client-id",
	ClientSecret: "your-client-secret",
	Scopes:       []string{"https://www.googleapis.com/auth/userinfo.email"},
	Endpoint:     google.Endpoint,
}

func handleGoogleLogin(w http.ResponseWriter, r *http.Request) {
	url := googleOauthConfig.AuthCodeURL("state-token")
	http.Redirect(w, r, url, http.StatusTemporaryRedirect)
}

func handleCallback(w http.ResponseWriter, r *http.Request) {
	code := r.URL.Query().Get("code")
	token, err := googleOauthConfig.Exchange(context.Background(), code)
	if err != nil {
		http.Error(w, "Ошибка обмена токена", http.StatusInternalServerError)
		return
	}

	// Получение данных пользователя
	client := googleOauthConfig.Client(context.Background(), token)
	resp, _ := client.Get("https://www.googleapis.com/oauth2/v2/userinfo")
	defer resp.Body.Close()

	var userInfo map[string]interface{}
	json.NewDecoder(resp.Body).Decode(&userInfo)
	fmt.Fprintf(w, "Email: %v", userInfo["email"])
}

func main() {
	http.HandleFunc("/auth/google", handleGoogleLogin)
	http.HandleFunc("/callback", handleCallback)
	http.ListenAndServe(":8080", nil)
}

3. Сессионная аутентификация

Классический подход с использованием куки и серверных сессий. В Go часто применяют библиотеку github.com/gorilla/sessions.

Установка:

go get github.com/gorilla/sessions

Пример реализации:

package main

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

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

func loginHandler(w http.ResponseWriter, r *http.Request) {
	session, _ := store.Get(r, "session-name")
	session.Values["authenticated"] = true
	session.Values["user_id"] = "user123"
	session.Save(r, w)
	fmt.Fprintf(w, "Вход выполнен")
}

func protectedHandler(w http.ResponseWriter, r *http.Request) {
	session, _ := store.Get(r, "session-name")
	if auth, ok := session.                    

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