session

package module
v1.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 10, 2018 License: Apache-2.0 Imports: 9 Imported by: 22

README

Session

Build Status GoDoc Go Report Card codecov

The Go standard library includes a nice http server, but unfortunately it lacks a very basic and important feature: HTTP session management.

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 in 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.

Documentation

Overview

Package session provides an easy-to-use, extensible and secure HTTP session implementation and management.

This is "just" an HTTP session implementation and management, you can use it as-is, or with any existing Go web toolkits and frameworks. Package documentation can be found and godoc.org:

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

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:

https://github.com/icza/session/blob/master/session_demo/session_demo.go

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:

https://github.com/icza/session/blob/master/gae_memcache_store.go

The implementation stores sessions in the Memcache and also saves sessions in 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.

https://github.com/icza/session/blob/master/gae_session_demo/gae_session_demo.go

Index

Constants

This section is empty.

Variables

Global is the default session Manager to which the top-level functions such as Get, Add, Remove and Close are wrappers of Manager. You may replace this and keep using the top-level functions, but if you intend to do so, you should close it first with Global.Close().

View Source
var NoopLogger = log.New(ioutil.Discard, "", 0)

NoopLogger that may be used as InMemStoreOptions.Logger to disable logging.

Functions

func Add

func Add(sess Session, w http.ResponseWriter)

Add delegates to Global.Add(); adds the session to the HTTP response. This means to let the client know about the specified session by including the sesison id in the response somehow.

func Close

func Close()

Close delegates to Global.Close(); closes the session manager, releasing any resources that were allocated.

func Remove

func Remove(sess Session, w http.ResponseWriter)

Remove delegates to Global.Remove(); removes the session from the HTTP response.

Types

type CookieManager

type CookieManager struct {
	// contains filtered or unexported fields
}

CookieManager is a secure, cookie based session Manager implementation. Only the session ID is transmitted / stored at the clients, and it is managed using cookies.

func (*CookieManager) Add

func (m *CookieManager) Add(sess Session, w http.ResponseWriter)

Add is to implement Manager.Add().

func (*CookieManager) Close

func (m *CookieManager) Close()

Close is to implement Manager.Close().

func (*CookieManager) CookieMaxAgeSec added in v1.2.0

func (m *CookieManager) CookieMaxAgeSec() int

CookieMaxAgeSec returns the Max age for session ID cookies in seconds.

func (*CookieManager) CookiePath added in v1.2.0

func (m *CookieManager) CookiePath() string

CookiePath returns the used cookie path.

func (*CookieManager) CookieSecure added in v1.2.0

func (m *CookieManager) CookieSecure() bool

CookieSecure tells if session ID cookies are to be sent only over HTTPS.

func (*CookieManager) Get

func (m *CookieManager) Get(r *http.Request) Session

Get is to implement Manager.Get().

func (*CookieManager) Remove

func (m *CookieManager) Remove(sess Session, w http.ResponseWriter)

Remove is to implement Manager.Remove().

func (*CookieManager) SessIDCookieName added in v1.2.0

func (m *CookieManager) SessIDCookieName() string

SessIDCookieName returns the name of the cookie used for storing the session ID.

type CookieMngrOptions

type CookieMngrOptions struct {
	// Name of the cookie used for storing the session ID; default value is "sessid"
	SessIDCookieName string

	// Tells if session ID cookies are allowed to be sent over unsecure HTTP too (else only HTTPS);
	// default value is false (only HTTPS)
	AllowHTTP bool

	// Max age for session ID cookies; default value is 30 days
	CookieMaxAge time.Duration

	// Cookie path to use; default value is the root: "/"
	CookiePath string
}

CookieMngrOptions defines options that may be passed when creating a new CookieManager. All fields are optional; default value will be used for any field that has the zero value.

type InMemStoreOptions

type InMemStoreOptions struct {
	// Session cleaner check interval, default is 10 seconds.
	SessCleanerInterval time.Duration

	// Logger to log session lifecycle events (e.g. added, removed, timed out).
	// Default is to use the global functions of the log package.
	// To disable logging, you may use NoopLogger.
	Logger *log.Logger
}

InMemStoreOptions defines options that may be passed when creating a new in-memory Store. All fields are optional; default value will be used for any field that has the zero value.

type Manager

type Manager interface {
	// Get returns the session specified by the HTTP request.
	// nil is returned if the request does not contain a session, or the contained session is not know by this manager.
	Get(r *http.Request) Session

	// Add adds the session to the HTTP response.
	// This means to let the client know about the specified session by including the sesison id in the response somehow.
	Add(sess Session, w http.ResponseWriter)

	// Remove removes the session from the HTTP response.
	Remove(sess Session, w http.ResponseWriter)

	// Close closes the session manager, releasing any resources that were allocated.
	Close()
}

Manager is a session manager interface. A session manager 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.

func NewCookieManager

func NewCookieManager(store Store) Manager

NewCookieManager creates a new, cookie based session Manager with default options. Default values of options are listed in the CookieMngrOptions type.

func NewCookieManagerOptions

func NewCookieManagerOptions(store Store, o *CookieMngrOptions) Manager

NewCookieManagerOptions creates a new, cookie based session Manager with the specified options.

type SessOptions

type SessOptions struct {
	// Constant attributes of the session. These be will available via the Session.CAttr() method, without synchronization.
	// Values from the map will be copied, and will be available via Session.CAttr().
	CAttrs map[string]interface{}

	// Initial, non-constant attributes to be stored in the session.
	// Values from the map will be copied, and will be available via Session.Attr() and Session.Attrs,
	// and may be changed with Session.SetAttr().
	Attrs map[string]interface{}

	// Session timeout, default is 30 minutes.
	Timeout time.Duration

	// Byte-length of the information that builds up the session ids.
	// Using Base-64 encoding, id length will be this multiplied by 4/3 chars.
	// Default value is 18 (which means length of ID will be 24 chars).
	IDLength int
}

SessOptions defines options that may be passed when creating a new Session. All fields are optional; default value will be used for any field that has the zero value.

type Session

type Session interface {
	// ID returns the id of the session.
	ID() string

	// New tells if the session is new.
	// Implementation is based on whether created and access times are equal.
	New() bool

	// CAttr returns the value of an attribute provided at session creation.
	// These attributes cannot be changes during the lifetime of a session,
	// so they can be accessed safely without synchronization. Exampe is storing the
	// authenticated user.
	CAttr(name string) interface{}

	// Attr returns the value of an attribute stored in the session.
	// Safe for concurrent use.
	Attr(name string) interface{}

	// SetAttr sets the value of an attribute stored in the session.
	// Pass the nil value to delete the attribute.
	// Safe for concurrent use.
	SetAttr(name string, value interface{})

	// Attrs returns a copy of all the attribute values stored in the session.
	// Safe for concurrent use.
	Attrs() map[string]interface{}

	// Created returns the session creation time.
	Created() time.Time

	// Accessed returns the time when the session was last accessed.
	Accessed() time.Time

	// Timeout returns the session timeout.
	// A session may be removed automatically if it is not accessed for this duration.
	Timeout() time.Duration

	// Mutex returns the RW mutex of the session.
	// It is used to synchronize access/modification of the state stored in the session.
	// It can be used if session-level synchronization is required.
	// Important! If Session values are marshalled / unmarshalled
	// (e.g. multi server instance environment such as Google AppEngine),
	// this mutex may be different for each Session value and thus
	// it can only be used to session-value level synchronization!
	Mutex() *sync.RWMutex

	// Access registers an access to the session,
	// updates its last accessed time to the current time.
	// Users do not need to call this as the session store is responsible for that.
	Access()
}

Session is the (HTTP) session interface. We can use it to store and retrieve constant and variable attributes from it.

func Get

func Get(r *http.Request) Session

Get delegates to Global.Get(); returns the session specified by the HTTP request. nil is returned if the request does not contain a session, or the contained session is not know by this manager.

func NewSession

func NewSession() Session

NewSession creates a new Session with the default options. Default values of options are listed in the SessOptions type.

func NewSessionOptions

func NewSessionOptions(o *SessOptions) Session

NewSessionOptions creates a new Session with the specified options.

type Store

type Store interface {
	// Get returns the session specified by its id.
	// The returned session will have an updated access time (set to the current time).
	// nil is returned if this store does not contain a session with the specified id.
	Get(id string) Session

	// Add adds a new session to the store.
	Add(sess Session)

	// Remove removes a session from the store.
	Remove(sess Session)

	// Close closes the session store, releasing any resources that were allocated.
	Close()
}

Store is a session store interface. A session store is responsible to store sessions and make them retrievable by their IDs at the server side.

func NewInMemStore

func NewInMemStore() Store

NewInMemStore returns a new, in-memory session Store with the default options. Default values of options are listed in the InMemStoreOptions type. The returned Store has an automatic session cleaner which runs in its own goroutine.

func NewInMemStoreOptions

func NewInMemStoreOptions(o *InMemStoreOptions) Store

NewInMemStoreOptions returns a new, in-memory session Store with the specified options. The returned Store has an automatic session cleaner which runs in its own goroutine.

Directories

Path Synopsis
This is a session demo application.
This is a session demo application.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL