Session middleware for elton v2, with a built-in memory store.
Session IDs can be carried by cookie (optionally signed), HTTP header, or any custom Get/Set pair.
go get github.com/vicanso/elton-session/v2Requires Go 1.24+.
Reads the session ID from a cookie. On first commit, writes Set-Cookie (HttpOnly is always forced).
package main
import (
"bytes"
"net/http"
"strconv"
"strings"
"time"
"github.com/rs/xid"
"github.com/vicanso/elton/v2"
session "github.com/vicanso/elton-session/v2"
)
func main() {
store, err := session.NewMemoryStore(10)
if err != nil {
panic(err)
}
e := elton.New()
signedKeys := &elton.RWMutexSignedKeys{}
signedKeys.SetKeys([]string{"cuttlefish"})
e.SignedKeys = signedKeys
e.Use(session.NewByCookie(session.CookieConfig{
Store: store,
Signed: true,
TTL: 10 * time.Hour,
GenID: func() string {
return strings.ToUpper(xid.New().String())
},
Cookie: http.Cookie{
Name: "jt",
Path: "/",
MaxAge: 24 * 3600,
Secure: true,
},
}))
e.GET("/", func(c *elton.Context) error {
se := session.MustFromContext(c)
views := se.GetInt("views")
_ = se.Set(c.Context(), "views", views+1)
c.BodyBuffer = bytes.NewBufferString("hello world " + strconv.Itoa(views))
return nil
})
if err := e.ListenAndServe(":3000"); err != nil {
panic(err)
}
}Reads the session ID from a request header. On first commit, writes the same header on the response.
e.Use(session.NewByHeader(session.HeaderConfig{
Store: store,
TTL: 10 * time.Hour,
GenID: func() string {
return strings.ToUpper(xid.New().String())
},
Name: "X-Session-ID",
}))e.Use(session.New(session.Config{
Store: store,
TTL: time.Hour,
GenID: generateID,
Get: func(c *elton.Context) (string, error) {
// read id from query, cookie, header, ...
return c.QueryParam("sid"), nil
},
Set: func(c *elton.Context, id string) error {
// write id back however you need
c.SetHeader("X-Session-ID", id)
return nil
},
}))store, err := session.NewMemoryStore(1024)
store, err := session.NewMemoryStoreByConfig(session.MemoryStoreConfig{
Size: 1024,
SaveAs: "/tmp/elton-session-store",
Interval: 60 * time.Second,
})
// When finished (e.g. process shutdown), stop background flush:
// store.StopFlush()Implement session.Store:
type Store interface {
Get(ctx context.Context, id string) ([]byte, error)
Set(ctx context.Context, id string, data []byte, ttl time.Duration) error
Destroy(ctx context.Context, id string) error
}Example Redis store:
type RedisStore struct {
client *redis.Client
prefix string
}
func (rs *RedisStore) key(id string) string {
return rs.prefix + id
}
func (rs *RedisStore) Get(ctx context.Context, id string) ([]byte, error) {
buf, err := rs.client.Get(ctx, rs.key(id)).Bytes()
if err == redis.Nil {
return nil, nil
}
return buf, err
}
func (rs *RedisStore) Set(ctx context.Context, id string, data []byte, ttl time.Duration) error {
return rs.client.Set(ctx, rs.key(id), data, ttl).Err()
}
func (rs *RedisStore) Destroy(ctx context.Context, id string) error {
return rs.client.Del(ctx, rs.key(id)).Err()
}se, ok := session.FromContext(c)
se = session.MustFromContext(c)
// typed getters (JSON-friendly casting)
se.GetString("account")
se.GetInt("views")
se.GetBool("admin")
// metadata
se.GetCreatedAt()
se.GetUpdatedAt()
se.GetExpiredAt()- Module path:
github.com/vicanso/elton-session/v2 - Depends on
github.com/vicanso/elton/v2andgithub.com/vicanso/hesv1 - Config field
Expired→TTL - Context key constant
Key→DefaultKey Get/MustGet→FromContext/MustFromContext(plusFromContextKey)Session.GetData()→Session.Data()CookieConfigcookie fields collapsed intoCookie http.Cookie- Cookie mode always forces
HttpOnly=true; emptyPathdefaults to"/" LazyFetchis honored byNewByCookie/NewByHeader(was ignored in v1)- Optional
Config.Key/CookieConfig.Key/HeaderConfig.Keyfor a custom context key - Errors use hes v1 options API (
WithCategory/WithStatus/WithException) interface{}→any- Memory store flush: ticker is stopped on
StopFlush; persistence usesos.ReadFile/os.WriteFile - Go 1.24+