21

I'm new to the Go language (Golang) and I'm writing a web-based application. I'd like to use session variables, like the kind in PHP (variables that are available from one page to the next and unique for a user session). Is there something like that in Go? If not, how would I go about implementing them myself? Or what alternatives methods are there?

icza
  • 289,344
  • 42
  • 658
  • 630
Ross Salas
  • 211
  • 1
  • 2
  • 3

3 Answers3

17

You probably want to take a look at gorilla. It has session support as documented here.

Other than that or possibly one of the other web toolkits for go you would have to roll your own.

Possible solutions might be:

  • goroutine per user session to store session variables in memory.
  • store your variables in a session cookie.
  • use a database to store user session data.

I'll leave the implementation details of each of those to the reader.

Roger Fan
  • 4,470
  • 25
  • 33
Jeremy Wall
  • 20,762
  • 4
  • 50
  • 72
  • 1
    Thanks for your reply. Do you know if I could get gorilla to work with GAE? – Ross Salas Jun 07 '12 at 15:24
  • It mentions something about AppEngine in it's documentation. But I haven't looked into it very deeply. – Jeremy Wall Jun 07 '12 at 20:35
  • @RossSalas take look at this: https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=2&cad=rja&ved=0CD0QFjAB&url=http%3A%2F%2Fcode.google.com%2Fp%2Fgorilla%2Fsource%2Fbrowse%2Fappengine%2Fsessions%2Fsessions.go%3Fr%3Dc83de7212a26509cc913c08655b08ccab8b7b3c0&ei=F18iUr6xD7KrsAS2ooHwCw&usg=AFQjCNG7b3dP1muJxN2efANgWeZJIq-HdQ&sig2=QzVhV7_5Fjr3qZSLC90DFQ&bvm=bv.51495398,d.cWc – Otuk Aug 31 '13 at 21:29
6

Here's an alternative in case you just want session support without a complete web toolkit.

https://github.com/bpowers/seshcookie

Linus Swälas
  • 120
  • 1
  • 6
5

Here's another alternative (disclosure: I'm the author):

https://github.com/icza/session

Quoting from its doc:


This package provides an easy-to-use, extensible and secure session implementation and management. Package documentation can be found and godoc.org:

https://godoc.org/github.com/icza/session

This is "just" an HTTP session implementation and management, you can use it as-is, or with any existing Go web toolkits and frameworks.

Overview

There are 3 key players in the package:

  • Session is the (HTTP) session interface. We can use it to store and retrieve constant and variable attributes from it.
  • Store is a session store interface which is responsible to store sessions and make them retrievable by their IDs at the server side.
  • Manager is a session manager interface which is responsible to acquire a Session from an (incoming) HTTP request, and to add a Session to an HTTP response to let the client know about the session. A Manager has a backing Store which is responsible to manage Session values at server side.

Players of this package are represented by interfaces, and various implementations are provided for all these players. You are not bound by the provided implementations, feel free to provide your own implementations for any of the players.

Usage

Usage can't be simpler than this. To get the current session associated with the http.Request:

sess := session.Get(r)
if sess == nil {
    // No session (yet)
} else {
    // We have a session, use it
}

To create a new session (e.g. on a successful login) and add it to an http.ResponseWriter (to let the client know about the session):

sess := session.NewSession()
session.Add(sess, w)

Let's see a more advanced session creation: let's provide a constant attribute (for the lifetime of the session) and an initial, variable attribute:

sess := session.NewSessionOptions(&session.SessOptions{
    CAttrs: map[string]interface{}{"UserName": userName},
    Attrs:  map[string]interface{}{"Count": 1},
})

And to access these attributes and change value of "Count":

userName := sess.CAttr("UserName")
count := sess.Attr("Count").(int) // Type assertion, you might wanna check if it succeeds
sess.SetAttr("Count", count+1)    // Increment count

(Of course variable attributes can be added later on too with Session.SetAttr(), not just at session creation.)

To remove a session (e.g. on logout):

session.Remove(sess, w)

Check out the session demo application which shows all these in action.

Google App Engine support

The package provides support for Google App Engine (GAE) platform.

The documentation doesn't include it (due to the +build appengine build constraint), but here it is: gae_memcache_store.go

The implementation stores sessions in the Memcache and also saves sessions to the Datastore as a backup in case data would be removed from the Memcache. This behaviour is optional, Datastore can be disabled completely. You can also choose whether saving to Datastore happens synchronously (in the same goroutine) or asynchronously (in another goroutine), resulting in faster response times.

We can use NewMemcacheStore() and NewMemcacheStoreOptions() functions to create a session Store implementation which stores sessions in GAE's Memcache. Important to note that since accessing the Memcache relies on Appengine Context which is bound to an http.Request, the returned Store can only be used for the lifetime of a request! Note that the Store will automatically "flush" sessions accessed from it when the Store is closed, so it is very important to close the Store at the end of your request; this is usually done by closing the session manager to which you passed the store (preferably with the defer statement).

So in each request handling we have to create a new session manager using a new Store, and we can use the session manager to do session-related tasks, something like this:

ctx := appengine.NewContext(r)
sessmgr := session.NewCookieManager(session.NewMemcacheStore(ctx))
defer sessmgr.Close() // This will ensure changes made to the session are auto-saved
                      // in Memcache (and optionally in the Datastore).

sess := sessmgr.Get(r) // Get current session
if sess != nil {
    // Session exists, do something with it.
    ctx.Infof("Count: %v", sess.Attr("Count"))
} else {
    // No session yet, let's create one and add it:
    sess = session.NewSession()
    sess.SetAttr("Count", 1)
    sessmgr.Add(sess, w)
}

Expired sessions are not automatically removed from the Datastore. To remove expired sessions, the package provides a PurgeExpiredSessFromDSFunc() function which returns an http.HandlerFunc. It is recommended to register the returned handler function to a path which then can be defined as a cron job to be called periodically, e.g. in every 30 minutes or so (your choice). As cron handlers may run up to 10 minutes, the returned handler will stop at 8 minutes to complete safely even if there are more expired, undeleted sessions. It can be registered like this:

http.HandleFunc("/demo/purge", session.PurgeExpiredSessFromDSFunc(""))

Check out the GAE session demo application which shows how it can be used. cron.yaml file of the demo shows how a cron job can be defined to purge expired sessions.

Check out the GAE session demo application which shows how to use this in action.

icza
  • 289,344
  • 42
  • 658
  • 630
  • I'm using your package but I don't think that .Remove() completely kills the session because I'm still able to access session variables after it is called. Any thoughts? This is what i'm using to kill a session: `session.Remove(sess, res)` and `sess = nil` – pascalallen Dec 23 '16 at 16:59
  • @pascalallen It works for me. Please post your code that reproduces the error. Please open an issue at https://github.com/icza/session/issues. – icza Dec 25 '16 at 08:38
  • Okay, I've created an issue on your GitHub explaining my issue, if you have moment would you mind looking at it? Thank you. Here is the link: [https://github.com/icza/session/issues/4](https://github.com/icza/session/issues/4) – pascalallen Dec 27 '16 at 16:00
  • @pascalallen Checking it now. – icza Dec 27 '16 at 17:17