package middleware import ( "context" "errors" "net/http" "go.neonxp.ru/mux" "go.neonxp.ru/mux/middleware/session" "go.neonxp.ru/objectid" ) type SessionConfig struct { SessionCookie string Path string Domain string Secure bool HttpOnly bool MaxAge int } var DefaultSessionConfig SessionConfig = SessionConfig{ SessionCookie: "_session", Path: "/", Domain: "", Secure: false, HttpOnly: true, MaxAge: 30 * 3600, } func Session(config SessionConfig, storer session.Store) mux.Middleware { return func(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { var ( sessionID string values session.Value ) cookie, err := r.Cookie(config.SessionCookie) switch { case err == nil: sessionID = cookie.Value values = storer.Load(r.Context(), sessionID) case errors.Is(err, http.ErrNoCookie): sessionID = objectid.New().String() values = session.Value{} } http.SetCookie(w, &http.Cookie{ Name: config.SessionCookie, Value: sessionID, Path: config.Path, Domain: config.Domain, Secure: config.Secure, HttpOnly: config.HttpOnly, MaxAge: config.MaxAge, }) ctx := context.WithValue(r.Context(), sessionValueKey, &values) ctx = context.WithValue(ctx, sessionIDKey, sessionID) ctx = context.WithValue(ctx, sessionConfigKey, config) ctx = context.WithValue(ctx, sessionStorerKey, storer) h.ServeHTTP(w, r.WithContext(ctx)) storer.Save(r.Context(), sessionID, values) }) } } func SessionFromRequest(r *http.Request) *session.Value { return r.Context().Value(sessionValueKey).(*session.Value) } func ClearSession(w http.ResponseWriter, r *http.Request) { storer := r.Context().Value(sessionStorerKey).(session.Store) sessionID := r.Context().Value(sessionIDKey).(string) storer.Remove(r.Context(), sessionID) config := r.Context().Value(sessionConfigKey).(SessionConfig) http.SetCookie(w, &http.Cookie{ Name: config.SessionCookie, Value: sessionID, Path: config.Path, Domain: config.Domain, Secure: config.Secure, HttpOnly: config.HttpOnly, MaxAge: -1, }) }