Официальное API SCS: Управление HTTP-сессиями для Go
Использование пользовательских хранилищ сеансов scs.Store определяет интерфейс для пользовательских хранилищ сеансов. Любой объект, реализующий этот интерфейс, может быть установлен как хранилище при настройке сеанса.
Работа с пользовательскими хранилищами сессий
Интерфейсы хранилищ
Базовый интерфейс Store
Определяет контракт для реализации пользовательских хранилищ:
type Store interface {
// Delete удаляет токен и данные сессии из хранилища
// Если токен не существует - операция должна завершиться успешно
Delete(token string) error
// Find ищет данные по токену сессии
// Возвращает:
// - данные (если найдены)
// - флаг found (найдено/не найдено)
// - ошибку (только для системных сбоев)
Find(token string) ([]byte, bool, error)
// Commit сохраняет или обновляет данные сессии
Commit(token string, data []byte, expiry time.Time) error
}
Интерфейс IterableStore
Добавляет возможность перебора всех сессий:
type IterableStore interface {
// All возвращает все активные (не истекшие) сессии
// В формате map[токен]данные
All() (map[string][]byte, error)
}
Версии с поддержкой контекста
CtxStore
Расширяет базовый интерфейс с добавлением context.Context:
type CtxStore interface {
Store
// Версии методов с поддержкой контекста
DeleteCtx(ctx context.Context, token string) error
FindCtx(ctx context.Context, token string) ([]byte, bool, error)
CommitCtx(ctx context.Context, token string, data []byte, expiry time.Time) error
}
IterableCtxStore
Аналогично для перебора сессий:
type IterableCtxStore interface {
AllCtx(ctx context.Context) (map[string][]byte, error)
}
Защита от фиксации сессии
Для предотвращения атак фиксации сессии необходимо:
func loginHandler(w http.ResponseWriter, r *http.Request) {
userID := 123
// 1. Сначала обновляем токен сессии
if err := sessionManager.RenewToken(r.Context()); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// 2. Затем сохраняем данные пользователя
sessionManager.Put(r.Context(), "userID", userID)
}
Ключевые моменты:
- Всегда обновляйте токен при изменении прав доступа
- Порядок операций критически важен
- Такой же подход применяйте при выходе пользователя
Это гарантирует, что после аутентификации будет создан новый токен сессии, делая недействительными любые ранее перехваченные токены.
Типы данных в SCS
Интерфейс Codec
Добавлен в v2.2.0
type Codec interface {
// Encode преобразует срок действия и значения сессии в байтовый срез
Encode(deadline time.Time, values map[string]interface{}) ([]byte, error)
// Decode восстанавливает срок действия и значения сессии из байтового среза
Decode([]byte) (deadline time.Time, values map[string]interface{}, err error)
}
Интерфейс для кодирования/декодирования данных сессии при работе с хранилищем.
Интерфейс CtxStore
Добавлен в v2.5.0
type CtxStore interface {
Store
// Версии методов с поддержкой контекста:
DeleteCtx(ctx context.Context, token string) error
FindCtx(ctx context.Context, token string) ([]byte, bool, error)
CommitCtx(ctx context.Context, token string, b []byte, expiry time.Time) error
}
Расширенный интерфейс хранилища с поддержкой context.Context.
Структура GobCodec
Добавлена в v2.3.1
type GobCodec struct{}
Реализация Codec с использованием encoding/gob для сериализации данных.
Методы GobCodec:
// Decode преобразует байты в срок действия и данные сессии
func (GobCodec) Decode(b []byte) (time.Time, map[string]interface{}, error)
// Encode сериализует данные сессии в байтовый срез
func (GobCodec) Encode(deadline time.Time, values map[string]interface{}) ([]byte, error)
Интерфейс IterableCtxStore
Добавлен в v2.5.0
type IterableCtxStore interface {
// AllCtx возвращает все активные сессии (с поддержкой контекста)
AllCtx(ctx context.Context) (map[string][]byte, error)
}
Интерфейс для перечислимых хранилищ с поддержкой context.Context.
Интерфейс IterableStore
Добавлен в v2.5.0
type IterableStore interface {
// All возвращает все активные (не истекшие) сессии
All() (map[string][]byte, error)
}
Базовый интерфейс для хранилищ с возможностью перебора сессий.
Ключевые особенности:
Codec
- абстракция для сериализации данныхGobCodec
- стандартная реализация через encoding/gobCtxStore
добавляет поддержку контекста к базовому хранилищу- Интерфейсы
Iterable
позволяют работать со всеми сессиями
Конфигурация сессий в SCS
Структура SessionCookie
type SessionCookie struct {
// Имя cookie сессии (не должно содержать спецсимволы)
// По умолчанию: "session"
Name string
// Домен cookie (по умолчанию - текущий домен)
Domain string
// HttpOnly флаг (по умолчанию true)
HttpOnly bool
// Путь cookie (по умолчанию "/")
Path string
// Сохранять cookie после закрытия браузера (по умолчанию true)
Persist bool
// Политика SameSite (по умолчанию Lax)
SameSite http.SameSite
// Secure флаг (только HTTPS, по умолчанию false)
Secure bool
}
Настройки cookie для управления сессиями.
Структура SessionManager
Добавлена в v2.1.0
type SessionManager struct {
// Таймаут бездействия (опционально)
IdleTimeout time.Duration
// Максимальное время жизни сессии (по умолчанию 24 часа)
Lifetime time.Duration
// Хранилище сессий
Store Store
// Настройки cookie
Cookie SessionCookie
// Кодек для сериализации данных (по умолчанию GobCodec)
Codec Codec
// Обработчик ошибок (по умолчанию HTTP 500)
ErrorFunc func(http.ResponseWriter, *http.Request, error)
// Хэшировать токен в хранилище
HashTokenInStore bool
// содержит скрытые поля
}
Основные настройки:
- IdleTimeout: автоматическое завершение неактивных сессий
- Lifetime: абсолютное время жизни сессии
- Store: подключение к Redis, PostgreSQL и другим хранилищам
- Cookie: тонкая настройка параметров безопасности cookie
- Codec: кастомная сериализация данных
- ErrorFunc: обработка ошибок на уровне middleware
Рекомендации по безопасности:
- Всегда устанавливайте
Secure=true
в production - Используйте
SameSite=Strict
для критичных операций - Для API можно отключить
HttpOnly
и работать через заголовки - Регулируйте
Lifetime
в соответствии с требованиями приложения
Пример инициализации:
manager := scs.New()
manager.Lifetime = 12 * time.Hour
manager.Cookie.Secure = true
manager.Cookie.SameSite = http.SameSiteStrictMode
manager.Store = redisstore.New(redisPool)
Методы SessionManager
Основные функции
New
Добавлено в v2.1.0
func New() *SessionManager
Создает новый менеджер сессий с настройками по умолчанию. Потокобезопасен.
Clear (устаревший)
func (s *SessionManager) Clear(ctx context.Context) error
Очищает все данные текущей сессии, не затрагивая токен и время жизни. Если данных нет - операция не выполняется.
Управление сессиями
Commit
Добавлено в v2.1.0
func (s *SessionManager) Commit(ctx context.Context) (string, time.Time, error)
Сохраняет данные сессии в хранилище и возвращает:
- Токен сессии
- Время истечения
- Ошибку (если есть)
Обычно используется автоматически middleware LoadAndSave()
.
Deadline
Добавлено в v2.5.0
func (s *SessionManager) Deadline(ctx context.Context) time.Time
Возвращает абсолютное время истечения сессии. При использовании IdleTimeout
сессия может завершиться раньше из-за неактивности.
Destroy
Добавлено в v2.1.0
func (s *SessionManager) Destroy(ctx context.Context) error
Полностью удаляет сессию:
- Удаляет данные из хранилища
- Помечает сессию как уничтоженную
- Новые операции создадут свежую сессию
Работа с данными
Exists
Добавлено в v2.1.0
func (s *SessionManager) Exists(ctx context.Context, key string) bool
Проверяет наличие ключа в данных сессии.
Get
Добавлено в v2.1.0
func (s *SessionManager) Get(ctx context.Context, key string) interface{}
Возвращает значение по ключу как interface{}
, требующее приведения типа:
foo, ok := session.Get(ctx, "foo").(string)
if !ok {
return errors.New("ошибка приведения типа")
}
GetBool
Добавлено в v2.1.0
func (s *SessionManager) GetBool(ctx context.Context, key string) bool
Возвращает значение как bool
(по умолчанию false
если ключ отсутствует или тип не совпадает).
GetBytes
Добавлено в v2.1.0
func (s *SessionManager) GetBytes(ctx context.Context, key string) []byte
Возвращает значение как []byte
(по умолчанию nil
).
Методы работы с данными сессии
Получение типизированных значений
GetFloat
func (s *SessionManager) GetFloat(ctx context.Context, key string) float64
Возвращает значение как float64
(0 если ключ отсутствует или тип не совпадает)
GetInt
func (s *SessionManager) GetInt(ctx context.Context, key string) int
Возвращает значение как int
(0 если ключ отсутствует)
GetInt32
func (s *SessionManager) GetInt32(ctx context.Context, key string) int32
Возвращает значение как int32
(0 по умолчанию)
GetInt64
func (s *SessionManager) GetInt64(ctx context.Context, key string) int64
Возвращает значение как int64
(0 по умолчанию)
GetString
func (s *SessionManager) GetString(ctx context.Context, key string) string
Возвращает строковое значение (пустая строка "" если ключ отсутствует)
GetTime
func (s *SessionManager) GetTime(ctx context.Context, key string) time.Time
Возвращает значение времени (time.IsZero() == true если ключ отсутствует)
Управление сессиями
Iterate
func (s *SessionManager) Iterate(ctx context.Context, fn func(context.Context) error) error
Итерируется по всем активным сессиям и выполняет функцию fn для каждой. Требует поддержки итерации в хранилище.
Keys
func (s *SessionManager) Keys(ctx context.Context) []string
Возвращает отсортированный список всех ключей сессии (пустой слайс если данных нет)
Middleware и загрузка данных
Load
func (s *SessionManager) Load(ctx context.Context, token string) (context.Context, error)
Загружает данные сессии по токену и возвращает новый контекст. Создает новую сессию если токен не найден.
LoadAndSave
func (s *SessionManager) LoadAndSave(next http.Handler) http.Handler
Middleware для автоматической загрузки/сохранения сессии и управления cookie.
Пример:
router := http.NewServeMux()
router.HandleFunc("/", handler)
// Обертывание роутера middleware
app := sessionManager.LoadAndSave(router)
http.ListenAndServe(":4000", app)
Методы управления сессиями в SCS
Работа с данными сессии
MergeSession (v2.5.0+)
func (s *SessionManager) MergeSession(ctx context.Context, token string) error
Объединяет данные из другой сессии (полезно при OAuth-редиректах). Для полной замены данных используйте Clear()
.
Pop-методы
Одноразовое получение данных с удалением ключа:
func (s *SessionManager) Pop(ctx context.Context, key string) interface{}
func (s *SessionManager) PopBool(ctx context.Context, key string) bool
func (s *SessionManager) PopBytes(ctx context.Context, key string) []byte
func (s *SessionManager) PopFloat(ctx context.Context, key string) float64
func (s *SessionManager) PopInt(ctx context.Context, key string) int
func (s *SessionManager) PopString(ctx context.Context, key string) string
func (s *SessionManager) PopTime(ctx context.Context, key string) time.Time
Пример для flash-сообщений:
// Установка
sessionManager.Put(ctx, "flash", "Сообщение")
// Получение с удалением
msg := sessionManager.PopString(ctx, "flash")
Основные операции
Put (v2.1.0+)
func (s *SessionManager) Put(ctx context.Context, key string, val interface{})
Добавляет или обновляет значение в сессии. Автоматически помечает сессию как измененную.
Remove (v2.1.0+)
func (s *SessionManager) Remove(ctx context.Context, key string)
Удаляет ключ из сессии. Если ключ не существует - операция игнорируется.
Управление токенами и временем жизни
RenewToken (v2.1.0+)
func (s *SessionManager) RenewToken(ctx context.Context) error
Генерирует новый токен сессии, сохраняя данные. Критично для:
- Входа/выхода пользователей
- Изменения прав доступа
- Защиты от фиксации сессии
RememberMe (v2.5.0+)
func (s *SessionManager) RememberMe(ctx context.Context, val bool)
Управляет постоянством сессии (работает только при Cookie.Persist = false
).
SetDeadline (v2.7.0+)
func (s *SessionManager) SetDeadline(ctx context.Context, expire time.Time)
Устанавливает абсолютное время истечения сессии (может быть перекрыто IdleTimeout
).
Информационные методы
Status (v2.1.0+)
func (s *SessionManager) Status(ctx context.Context) Status
Возвращает текущее состояние сессии (новые/измененные/уничтоженные).
Token (v2.5.0+)
func (s *SessionManager) Token(ctx context.Context) string
Возвращает токен сессии (пустую строку до коммита).
WriteSessionCookie (v2.3.0+)
func (s *SessionManager) WriteSessionCookie(ctx context.Context, w http.ResponseWriter, token string, expiry time.Time)
Низкоуровневый метод записи cookie (обычно используется через middleware).
Типы данных и интерфейсы SCS
Тип Status
type Status int
Статус представляет состояние данных сессии в течение цикла запроса.
Константы статусов:
const (
// Unmodified - данные сессии не изменялись
Unmodified Status = iota
// Modified - данные были изменены
Modified
// Destroyed - сессия была уничтожена
Destroyed
)
Использование:
status := sessionManager.Status(ctx)
switch status {
case scs.Unmodified:
// Сессия не изменялась
case scs.Modified:
// Требуется сохранение изменений
case scs.Destroyed:
// Сессия закрыта
}
Интерфейс Store
type Store interface {
// Delete удаляет токен и данные сессии
// Если токен не существует - операция игнорируется
Delete(token string) error
// Find ищет данные по токену сессии
// Возвращает:
// - данные (если найдены)
// - флаг существования
// - ошибку (только для системных сбоев)
Find(token string) ([]byte, bool, error)
// Commit сохраняет/обновляет данные сессии
Commit(token string, data []byte, expiry time.Time) error
}
Базовый интерфейс для реализации хранилищ сессий.
Особенности реализации:
- Delete должен быть идемпотентным
- Find возвращает
found=false
для:- Несуществующих токенов
- Истекших сессий
- Поврежденных данных
- Commit должен перезаписывать существующие данные
Пример проверки сессии:
data, found, err := store.Find(token)
if err != nil {
// Обработка системной ошибки
}
if !found {
// Сессия не существует/истекла
}
Этот интерфейс позволяет интегрировать SCS с любыми системами хранения данных.