Авторизация и аутентификация в 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.