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