Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best practice with sessions (gorilla/sessions)

Tags:

session

go

Before starting using sessions in golang I need answers to some questions

session example

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,
    }
}

Q1:

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?

Q2:

What is the best practice to get the variables from the session? my_session_var = session.Values["foo"]

Q3:

How to check if the session is saved correctly? If you access the same map to both set and get variables?

update

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
like image 316
clarkk Avatar asked Sep 29 '14 18:09

clarkk


People also ask

What is Gorilla/sessions in GitHub?

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.

How to encrypt a gorilla session cookie?

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.

How do I get Started with the sessions API?

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.


1 Answers

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:

  • the session management (clone/close)
  • 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".

like image 98
VonC Avatar answered Sep 19 '22 08:09

VonC