gorilla/sessions

[question] Sessions not persisted after server restart?

jerlam06 opened this issue · 2 comments

I am not sure if it is a normal behavior or not. My sessions are persisted correctly while my server is running, but as soon as I restart it the sessions fail to be retrieved:

package session

import (
	"encoding/gob"
	"fmt"
	"net/http"

	"github.com/jerlam06/go-gql-server/internal/logger"
	myredis "github.com/jerlam06/go-gql-server/pkg/redis"
	"github.com/jerlam06/go-gql-server/pkg/utils"

	"github.com/gorilla/sessions"
	"gopkg.in/boj/redistore.v1"
)

var (
	//Store Redis store
	Store *redistore.RediStore

	sessionStoreSecret string = utils.MustGet("REDIS_SESSION_STORE_SECRET")
	domainName         string = utils.MustGet("GQL_SERVER_HOST")
	sessionTimeOut     int
)

// SessionObj struct that hold the session
type SessionObj struct {
	ID       string
	Email    string
	Username string
	PublicID int
}

// InitSessionStore Create session store
func InitSessionStore() {
	sessionTimeOut = 300

	rediStore, err := redistore.NewRediStoreWithPool(myredis.Pool, []byte(sessionStoreSecret))
	rediStore.DefaultMaxAge = sessionTimeOut

	if err != nil {
		panic(err)
	}
	Store = rediStore

	logger.Info("[Redis Store] Registering session object")
	gob.Register(SessionObj{})
}

// GetSession get the session
func GetSession(r *http.Request, sessName, sessKey string) (sessObj *SessionObj, err error) {

	// Get a session.
	sess, err := Store.Get(r, sessName)

	if err != nil {
		logger.Error(err.Error())
	}

	fmt.Println(sess)
	if obj, ok := sess.Values[sessKey].(SessionObj); !ok {
		logger.Errorf("Session not found for key %s", sessKey)
		err = fmt.Errorf("Session not found for key %s", sessKey)
	} else {
		sessObj = &obj
	}
	return sessObj, err
}

// SaveSession save session
func SaveSession(r *http.Request, w http.ResponseWriter, sessName, sessKey string, sessionObj *SessionObj, sessPrefix string) {
	SaveSessionToStore(r, w, sessName, sessKey, sessionTimeOut, sessionObj, sessPrefix)
}

// SaveSessionToStore save session
func SaveSessionToStore(r *http.Request, w http.ResponseWriter, sessName, sessKey string, timeout int, sessionObj *SessionObj, sessPrefix string) {
	Store.SetKeyPrefix(sessPrefix)
	// Get a session.
	sess, err := Store.Get(r, sessName)
	if err != nil {
		logger.Error(err.Error())
	}
	sess.Values[sessKey] = sessionObj

	if sessionObj != nil {
		logger.Infof("New session created for %s", sessKey)
	}

	sess.Options = &sessions.Options{
		// Domain:   domainName,
		Path:     "/",
		MaxAge:   timeout,
		HttpOnly: true,
	}

	if err = sess.Save(r, w); err != nil {
		logger.Fatalf("Error saving session: %v", err)
	}
}

And here is in my login resolver:

session.SaveSession(&h.Request, h.ResponseWriter, sessName, "sessionID", sessObj, sessPrefix)

Note that the KEYS are still there in Redis, and the cookies are also still there in the browser.

EDIT: After some investigation, I found out what was causing this issue. I am using Store.SetKeyPrefix(sessPrefix) when I save the session. So the KeyPrefix is set for all the lifetime of the Store. But when I restart the server, the Store is renewed and the KeyPrefix is back to default session_.
I could "fix" it by setting the KeyPrefix when I Get() the session, but this is causing troubles because the KeyPrefix is actually "user:1_" (1 stands for the publicID of the current user). As I call Store.Get() in my Me resolver, I have no access to the current user ID yet, because I am actually trying to retrieve it from SessionObj...
The reason why I want to use "user:" + user.ID as Prefix is to handle the deletion of all the sessions of a user when the latter logs out. So that I can find all the KEYS starting with "user:1_" in my Redis store, and delete them all at once.

Do you have any idea how I could achieve that? Is using KeyPrefix the only way?

Thanks :)

stale commented

This issue has been automatically marked as stale because it hasn't seen a recent update. It'll be automatically closed in a few days.