大猩猩/会话:在处理程序之间管理会话(持久更改)?

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!