Before starting using sessions in golang I need answers to some questions
import "github.com/gorilla/sessions"
var store = sessions.NewCookieStore([]byte("33446a9dcf9ea060a0a6532b166da32f304af0de"))
func Handler(w http.ResponseWriter, r *http.Request){
session, _ := store.Get(r, "session-name")
session.Values["foo"] = "bar"
session.Values[42] = 43
session.Save(r, w)
fmt.Fprint(w, "Hello world :)")
}
func main(){
store.Options = &sessions.Options{
Domain: "localhost",
Path: "/",
MaxAge: 60 * 15,
Secure: false,
HttpOnly: true,
}
}
Is it possible to add multiple sessions on the same domain with different names?
session1, _ := store.Get(r, "session-name-1")
session2, _ := store.Get(r, "session-name-2")
When do you need multiple sessions on the same domain?
What is the best practice to get the variables from the session? my_session_var = session.Values["foo"]
How to check if the session is saved correctly? If you access the same map
to both set and get variables?
package main
import (
"github.com/gorilla/sessions"
)
var (
store = sessions.NewCookieStore([]byte("33446a9dcf9ea060a0a6532b166da32f304af0de"))
)
type handler func(w http.ResponseWriter, r *http.Request, s *sessions.Session)
func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request){
session, _ := store.Get(r, "session-name")
h(w, r, session)
}
func Handler_404(w http.ResponseWriter, r *http.Request, s *sessions.Session){
fmt.Fprint(w, "Oops, something went wrong!")
}
error
# command-line-arguments
.\mux.go:101: cannot convert Handler_404 (type func(http.ResponseWriter, *http.Request, *sessions.Session)) to type http.HandlerFunc
GitHub - gorilla/sessions: Package gorilla/sessions provides cookie and filesystem sessions and infrastructure for custom session backends. Failed to load latest commit information. gorilla/sessions provides cookie and filesystem sessions and infrastructure for custom session backends.
Also note that with gorilla/sessions you should pass both an authKey and an encryptionKey if you wish to encrypt the cookie contents. Generate these once-off with crypto/rand or openssl CLI and store the values in a file that is only readable by the application user.
Let's start with an example that shows the sessions API in a nutshell: import ( "net/http" "github.com/gorilla/sessions" ) // Note: Don't store your key in your source code. Pass it via an // environmental variable, or flag (or both), and don't accidentally commit it // alongside your code.
The article "BASIC EXTENSION OF GO’S HTTP HANDLERS" (Simon Whitehead) shows an example of where and when to define session.
Instead of doing it in the Handler
itself, and having to duplicate a lot of code when you define other Handlers.
With a named type, you can define the Handler
you need:
type handler func(w http.ResponseWriter, r *http.Request, db *mgo.Database)
(in your case, it would be a gorilla sessions instead of a mgo session or database)
The init()
function can take care of the session creation (here mgo session, but the idea is the same for other framework sessions)
func init() {
session, err = mgo.Dial("localhost")
if err != nil {
log.Println(err)
}
}
And you can make sure this function type ('handler
') does respect the ServeHTTP()
function, taking care of:
calling your actual handler (which can have more parameters than just w
and r
)
func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
s := session.Clone()
defer s.Close()
h(w, r, s.DB("example"))
}
Then you can define your actual Handler
(again, with more than w
and r
):
func myHandler(w http.ResponseWriter, r *http.Request, db *mgo.Database) {
var users []user
db.C("users").Find(nil).All(&users)
for _, user := range users {
fmt.Fprintf(w, "%s is %d years old", user.Name, user.Age)
}
}
And you can use that handler in your server:
func main() {
mux := http.NewServeMux()
mux.Handle("/", handler(myHandler))
http.ListenAndServe(":8080", mux)
}
The idea is to limit the "plumbing" in main()
to a minimum, while having an Handler
with more parameters (including your session).
That allows you to use different Handlers
with very little plumbing, keeping main()
only for the declaration of the different path (and not for the initialization of session and handlers)
Update 2019: in another related context, see also "How to handle sessions".
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With