Ответ
В Go, как и в других языках для бэкенда, важно различать два понятия:
- Аутентификация (Authentication, AuthN) — это процесс проверки личности пользователя. Ответ на вопрос: «Кто вы?».
- Авторизация (Authorization, AuthZ) — это процесс проверки прав доступа пользователя к определенным ресурсам. Ответ на вопрос: «Что вам разрешено делать?».
Существует два основных подхода к их реализации:
1. Token-based (на основе токенов)
Это самый популярный stateless-подход для современных API и микросервисов. Наиболее распространенный стандарт — JWT (JSON Web Token).
Процесс:
- Пользователь отправляет логин и пароль.
- Сервер проверяет их, и в случае успеха генерирует JWT, подписывая его секретным ключом.
- Токен возвращается клиенту, который сохраняет его (например, в
localStorageилиcookie). - При каждом последующем запросе к защищенным ресурсам клиент отправляет этот токен в заголовке
Authorization: Bearer <token>. - Сервер проверяет подпись и срок действия токена. Если все в порядке, он извлекает из токена информацию о пользователе (ID, роли) и предоставляет доступ.
Пример с использованием github.com/golang-jwt/jwt/v5 (актуальная библиотека):
import (
"time"
"github.com/golang-jwt/jwt/v5"
)
var jwtKey = []byte("your_secret_key")
type Claims struct {
UserID int64 `json:"user_id"`
jwt.RegisteredClaims
}
// Генерация токена
func generateJWT(userID int64) (string, error) {
expirationTime := time.Now().Add(24 * time.Hour)
claims := &Claims{
UserID: userID,
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(expirationTime),
},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return token.SignedString(jwtKey)
}
// Валидация токена
func validateJWT(tokenStr string) (*Claims, error) {
claims := &Claims{}
token, err := jwt.ParseWithClaims(tokenStr, claims, func(token *jwt.Token) (interface{}, error) {
return jwtKey, nil
})
if err != nil {
return nil, err
}
if !token.Valid {
return nil, errors.New("invalid token")
}
return claims, nil
}
2. Session-based (на основе сессий)
Это классический stateful-подход, часто используемый в монолитных веб-приложениях.
Процесс:
- Пользователь отправляет логин и пароль.
- Сервер проверяет их и создает сессию, сохраняя ее ID и данные пользователя у себя (в памяти, Redis, базе данных).
- Клиенту в
cookieотправляется только идентификатор сессии. - При каждом запросе браузер автоматически отправляет
cookieс ID сессии. - Сервер находит сессию по ID и получает данные пользователя.
Для этого подхода в Go часто используется пакет gorilla/sessions.
В современных веб-фреймворках (Gin, Echo, Chi) проверка токенов или сессий обычно выносится в middleware, который защищает определенные эндпоинты.
Ответ 18+ 🔞
А, слушай, вот эта тема про авторизацию и аутентификацию — это ж классика, блядь! Вечный спор, как и что делать, а в итоге все упирается в два простых вопроса, ёпта. Первый: «Ты кто такой, сука?» — это аутентификация. В второй: «А тебе сюда можно, пидорас?» — это уже авторизация. Вот и вся философия, в рот меня чих-пых!
Ну и способов это организовать — как говна за баней, но основных два, блядь. И они, сука, как два брата-близнеца, только один — умный, а второй — дурак, который всё хранит у себя в голове.
Первый способ — на токенах. Модный, молодёжный, stateless, блядь. Как JWT, например. Суть проще пареной репы:
- Ты приползаешь к серверу, сука, с логином и паролем.
- Сервер тебя проверяет и, если ты не конченый мудак, выдает бумажку (токен), которую сам же и подписал своим секретным ключом. Типа, «предъявителю сего разрешается не быть мудаком».
- Ты эту бумажку засовываешь куда подальше (в
localStorageили куки) и таскаешь с собой. - Дальше, когда лезешь куда-то закрытое, ты просто суёшь эту бумажку в заголовок:
Authorization: Bearer <твой_токен_тут>. - Сервер смотрит на подпись и срок годности. Если не просрочен и подпись его — значит свой, блядь, пускает. Всю инфу о тебе (ID, роли) он прямо из токена выковыривает. Удобно, ёпта!
Вот тебе кусочек кода на Go, чтоб не быть голословным, как мартышлюшка. Библиотека github.com/golang-jwt/jwt/v5, не хуйню какую-то:
import (
"time"
"github.com/golang-jwt/jwt/v5"
)
var jwtKey = []byte("your_secret_key") // Ключик, блядь, храни как зеницу ока!
type Claims struct {
UserID int64 `json:"user_id"` // Вот твой ID, например
jwt.RegisteredClaims
}
// Функция, которая штампует эти бумажки
func generateJWT(userID int64) (string, error) {
expirationTime := time.Now().Add(24 * time.Hour) // Годен сутки, не больше
claims := &Claims{
UserID: userID,
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(expirationTime),
},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) // Подписываем
return token.SignedString(jwtKey)
}
// А это функция, которая проверяет, не подделка ли
func validateJWT(tokenStr string) (*Claims, error) {
claims := &Claims{}
token, err := jwt.ParseWithClaims(tokenStr, claims, func(token *jwt.Token) (interface{}, error) {
return jwtKey, nil // Даём ключ на проверку подписи
})
if err != nil {
return nil, err // Токен кривой, нахуй
}
if !token.Valid {
return nil, errors.New("invalid token") // Невалидный, просроченный
}
return claims, nil // Всё чики-пуки, вот твои claims
}
Второй способ — сессии. Это как старый дед, который всё помнит, но память у него уже дырявая, блядь. Stateful подход.
- Ты опять лезешь с логином-паролем.
- Сервер создаёт у себя в базе или в Redis запись (сессию), а тебе в куки пихает только её ID — типа номерок в гардеробе.
- Потом, когда ты ходишь по сайту, браузер сам, сука, этот номерок в каждом запросе показывает.
- Сервер по номерку находит твою сессию, смотрит, кто ты, и решает, пускать ли.
- Для этого в Go часто используют
gorilla/sessions. Проще, но серверу приходится всё помнить, ёбаный в рот!
И главное, блядь, в любом нормальном фреймворке (Gin, Echo, Chi) эту всю хуйню с проверкой засовывают в middleware. Чтобы не писать на каждом эндпоинте «эй, а ты кто?», а просто обернуть маршрут в защитный слой, и всё, пиздец. Красота!