I am using for Go session management:
"github.com/gorilla/sessions"
The problem with the following code is that the session associated with a CookieStore is not getting shared between handlers, and I need it to do such.
Handler "/authorize"
saves a value to the session and then redirects to another handler "/thankyou"
, but that handler does not see the value within the session.
I have validated that the session does have the new value within the originating handler "/authorize"
.
import (
"github.com/gorilla/sessions"
)
var (
cookieStore *sessions.CookieStore
storeGUID string
sessionGUID string
)
func init() {
storeGUID = "{random-string}"
sessionGUID = "{random-string}"
cookieStore = sessions.NewCookieStore([]byte(storeGUID))
}
mux.HandleFunc("/authorize", func(w http.ResponseWriter, r *http.Request) {
var sess *sessions.Session
sess, err := cookieStore.Get(r, sessionGUID)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
sess.Values["authMode"] = "Authorized"
if err := sess.Save(r, w); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// Redirect to "/thankyou"
authorizeURL := r.URL.String()
thankyouRedirectURL := strings.Replace(authorizeURL, "authorize", "thankyou", 1)
defer http.Redirect(w, r, thankyouRedirectURL, http.StatusFound)
}
mux.HandleFunc("/thankyou", func(w http.ResponseWriter, r *http.Request) {
var sess *sessions.Session
sess, err := cookieStore.Get(r, sessionGUID)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
var sval interface{}
var authMode string
sval = sess.Values["authMode"]
if authMode, ok := sval.(string); !ok {
err := errors.New("Missing \"authSess\" in session.")
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}
I ran into the same thing with my webserver. I was doing exactly what you're doing here:
sval = sess.Values["authMode"]
if authMode, ok := sval.(string); !ok {
err := errors.New("Missing \"authSess\" in session.")
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
I created a local variable in order to store the retrieved session value and then type asserted the value to ensure it's integrity. I discovered that the type assertion was silently failing, because the Values field of the gorilla/sessions.Session struct is of the type map[interface{}]interface{}
(source). When retrieving the session value from the Values field, as you do here...
sval = sess.Values["authMode"]
...the compiler thinks that sval is now of the interface{}
type. So, when you attempt to type assert sval, it fails to convert the interface to a string.
What I did was create a variable declaration above the if-block where i'm handling the type assertion, so that I can use it later on. Then, I type assert using the map element itself. This is what it would look like for you:
var authMode string // a var declaration with the type you want
var ok bool // in my case, I also created a bool var to avoid a pointer error
// directly type assert the session value
if authMode, ok = sess.Values["authMode"].(string); !ok {
err := errors.New("Missing \"authSess\" in session.")
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
I hope that helps!