diff options
author | Alexander NeonXP Kiryukhin <i@neonxp.ru> | 2024-07-30 00:45:25 +0300 |
---|---|---|
committer | Alexander NeonXP Kiryukhin <i@neonxp.ru> | 2024-07-30 00:45:25 +0300 |
commit | 623eaf165a4f248681acfec094f2f1ac1e0ff89f (patch) | |
tree | 54a7b7c0be2002b4d9c4d59081e0e9c2bb84628b /middleware/session/session.go | |
parent | c261597b9adb827bfa16de8f21ce47ac63bec138 (diff) |
Пересмотрел механизм сессий
Diffstat (limited to 'middleware/session/session.go')
-rw-r--r-- | middleware/session/session.go | 114 |
1 files changed, 74 insertions, 40 deletions
diff --git a/middleware/session/session.go b/middleware/session/session.go index 4d02bf1..47fc0fb 100644 --- a/middleware/session/session.go +++ b/middleware/session/session.go @@ -4,10 +4,9 @@ import ( "context" "errors" "net/http" - "sync" + "time" "go.neonxp.ru/mux" - "go.neonxp.ru/mux/middleware" "go.neonxp.ru/objectid" ) @@ -17,7 +16,7 @@ type Config struct { Domain string Secure bool HttpOnly bool - MaxAge int + MaxAge time.Duration } var DefaultConfig Config = Config{ @@ -26,69 +25,104 @@ var DefaultConfig Config = Config{ Domain: "", Secure: false, HttpOnly: true, - MaxAge: 30 * 3600, + MaxAge: 365 * 24 * time.Hour, } -func Middleware(config Config, storer Store) mux.Middleware { - if storer == nil { - storer = &MemoryStore{store: sync.Map{}} +var ( + ErrSessionNotFound = errors.New("session not found") + ErrNoSessionInContext = errors.New("no session in context") +) + +type SessionManager struct { + config *Config + storer Store +} + +func New(storer Store) *SessionManager { + return NewWithConfig(&DefaultConfig, storer) +} + +func NewWithConfig(config *Config, storer Store) *SessionManager { + return &SessionManager{ + config: config, + storer: storer, } +} +func (s *SessionManager) Middleware() mux.Middleware { return func(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { var ( sessionID string - values Value + values Values ) - cookie, err := r.Cookie(config.SessionCookie) + cookie, err := r.Cookie(s.config.SessionCookie) switch { case err == nil: sessionID = cookie.Value - values = storer.Load(r.Context(), sessionID) + values = s.storer.Load(sessionID) case errors.Is(err, http.ErrNoCookie): sessionID = objectid.New().String() - values = 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(), middleware.SessionValueKey, &values) - ctx = context.WithValue(ctx, middleware.SessionIDKey, sessionID) - ctx = context.WithValue(ctx, middleware.SessionConfigKey, config) - ctx = context.WithValue(ctx, middleware.SessionStorerKey, storer) + ctx := context.WithValue(r.Context(), sessionManagerKey, s) + ctx = context.WithValue(ctx, sessionIDKey, sessionID) + ctx = context.WithValue(ctx, sessionValueKey, values) h.ServeHTTP(w, r.WithContext(ctx)) - - storer.Save(r.Context(), sessionID, values) - }) } } -func FromRequest(r *http.Request) *Value { - return r.Context().Value(middleware.SessionValueKey).(*Value) +func (s *SessionManager) Values(ctx context.Context) Values { + aValue := ctx.Value(sessionValueKey) + values, ok := aValue.(Values) + if !ok || values == nil { + values = Values{} + } + + return values } -func Clear(w http.ResponseWriter, r *http.Request) { - storer := r.Context().Value(middleware.SessionStorerKey).(Store) - sessionID := r.Context().Value(middleware.SessionIDKey).(string) - storer.Remove(r.Context(), sessionID) - config := r.Context().Value(middleware.SessionConfigKey).(Config) +func (s *SessionManager) Save(w http.ResponseWriter, r *http.Request, values Values) error { + aSessionID := r.Context().Value(sessionIDKey) + sessionID, ok := aSessionID.(string) + if !ok { + return ErrNoSessionInContext + } + http.SetCookie(w, &http.Cookie{ - Name: config.SessionCookie, + Name: s.config.SessionCookie, Value: sessionID, - Path: config.Path, - Domain: config.Domain, - Secure: config.Secure, - HttpOnly: config.HttpOnly, + Path: s.config.Path, + Domain: s.config.Domain, + Secure: s.config.Secure, + HttpOnly: s.config.HttpOnly, + MaxAge: int(s.config.MaxAge.Seconds()), + }) + + return s.storer.Save(sessionID, values) +} +func (s *SessionManager) Clear(w http.ResponseWriter, r *http.Request) error { + aSessionID := r.Context().Value(sessionIDKey) + sessionID, ok := aSessionID.(string) + if !ok { + return ErrNoSessionInContext + } + + http.SetCookie(w, &http.Cookie{ + Name: s.config.SessionCookie, + Value: sessionID, + Path: s.config.Path, + Domain: s.config.Domain, + Secure: s.config.Secure, + HttpOnly: s.config.HttpOnly, MaxAge: -1, }) + + return s.storer.Remove(sessionID) +} + +func FromRequest(r *http.Request) *SessionManager { + return r.Context().Value(sessionManagerKey).(*SessionManager) } |