session

package
v0.1.1 Latest Latest
Warning

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

Go to latest
Published: Aug 6, 2017 License: MIT Imports: 15 Imported by: 0

Documentation

Overview

Package session provides session management middleware and helpers for manipulating session data.

It should be installed alongside one of the storage engines from https://godoc.org/github.com/alexedwards/scs/engine.

For example:

$ go get github.com/alexedwards/scs/session
$ go get github.com/alexedwards/scs/engine/memstore

Basic use:

package main

import (
    "io"
    "net/http"

    "github.com/alexedwards/scs/engine/memstore"
    "github.com/alexedwards/scs/session"
)

func main() {
    // Initialise a new storage engine. Here we use the memstore package, but the principles
    // are the same no matter which back-end store you choose.
    engine := memstore.New(0)

    // Initialise the session manager middleware, passing in the storage engine as
    // the first parameter. This middleware will automatically handle loading and
    // saving of session data for you.
    sessionManager := session.Manage(engine)

    // Set up your HTTP handlers in the normal way.
    mux := http.NewServeMux()
    mux.HandleFunc("/put", putHandler)
    mux.HandleFunc("/get", getHandler)

    // Wrap your handlers with the session manager middleware.
    http.ListenAndServe(":4000", sessionManager(mux))
}

func putHandler(w http.ResponseWriter, r *http.Request) {
    // Use the PutString helper to store a new key and associated string value in
    // the session data. Helpers are also available for bool, int, int64, float,
    // time.Time and []byte data types.
    err := session.PutString(r, "message", "Hello from a session!")
    if err != nil {
        http.Error(w, err.Error(), 500)
    }
}

func getHandler(w http.ResponseWriter, r *http.Request) {
    // Use the GetString helper to retrieve the string value associated with a key.
    msg, err := session.GetString(r, "message")
    if err != nil {
        http.Error(w, err.Error(), 500)
        return
    }
    io.WriteString(w, msg)
}

Index

Constants

This section is empty.

Variables

View Source
var ContextName = "scs.session"

ContextName changes the value of the (string) key used to store the session information in Request.Context. You should only need to change this if there is a naming clash.

View Source
var CookieName = "scs.session.token"

CookieName changes the name of the session cookie issued to clients. Note that cookie names should not contain whitespace, commas, semicolons, backslashes or control characters as per RFC6265.

View Source
var ErrAlreadyWritten = errors.New("session already written to the engine and http.ResponseWriter")

ErrAlreadyWritten is returned when an attempt is made to modify the session data after it has already been sent to the storage engine and client.

View Source
var ErrTypeAssertionFailed = errors.New("type assertion failed")

ErrTypeAssertionFailed is returned by operations on session data where the received value could not be type asserted or converted into the required type.

Functions

func Clear

func Clear(r *http.Request) error

Clear removes all data for the current session. The session token and lifetime are unaffected. If there is no data in the current session this operation is a no-op.

func Destroy

func Destroy(w http.ResponseWriter, r *http.Request) error

Destroy deletes the current session. The session token and accompanying data are deleted from the storage engine, and the client is instructed to delete the session cookie.

Destroy operations are effective immediately, and any further operations on the session in the same request cycle will return an ErrAlreadyWritten error. If you see this error you probably want to use the Renew function instead.

A new empty session will be created for any client that subsequently tries to use the destroyed session token.

func Exists

func Exists(r *http.Request, key string) (bool, error)

Exists returns true if the given key is present in the session data.

func GetBool

func GetBool(r *http.Request, key string) (bool, error)

GetBool returns the bool value for a given key from the session data. The zero value for a bool (false) is returned if the key does not exist. An ErrTypeAssertionFailed error is returned if the value could not be type asserted to a bool.

func GetBytes

func GetBytes(r *http.Request, key string) ([]byte, error)

GetBytes returns the byte slice ([]byte) value for a given key from the session data. The zero value for a slice (nil) is returned if the key does not exist. An ErrTypeAssertionFailed error is returned if the value could not be type asserted or converted to []byte.

func GetFloat

func GetFloat(r *http.Request, key string) (float64, error)

GetFloat returns the float64 value for a given key from the session data. The zero value for an float (0) is returned if the key does not exist. An ErrTypeAssertionFailed error is returned if the value could not be type asserted or converted to a float64.

func GetInt

func GetInt(r *http.Request, key string) (int, error)

GetInt returns the int value for a given key from the session data. The zero value for an int (0) is returned if the key does not exist. An ErrTypeAssertionFailed error is returned if the value could not be type asserted or converted to a int.

func GetInt64

func GetInt64(r *http.Request, key string) (int64, error)

GetInt64 returns the int64 value for a given key from the session data. The zero value for an int (0) is returned if the key does not exist. An ErrTypeAssertionFailed error is returned if the value could not be type asserted or converted to a int64.

func GetObject

func GetObject(r *http.Request, key string, dst interface{}) error

GetObject reads the data for a given session key into an arbitrary object (represented by the dst parameter). It should only be used to retrieve custom data types that have been stored using PutObject. The object represented by dst will remain unchanged if the key does not exist.

The dst parameter must be a pointer.

Usage:

// Note that the fields on the custom type are all exported.
type User struct {
    Name  string
    Email string
}

func getHandler(w http.ResponseWriter, r *http.Request) {
    // Register the type with the encoding/gob package. Usually this would be
    // done in an init() function.
    gob.Register(User{})

    // Initialise a pointer to a new, empty, custom object.
    user := &User{}

    // Read the custom object data from the session into the pointer.
    err := session.GetObject(r, "user", user)
    if err != nil {
        http.Error(w, err.Error(), 500)
        return
    }
    fmt.Fprintf(w, "Name: %s, Email: %s", user.Name, user.Email)
}

func GetString

func GetString(r *http.Request, key string) (string, error)

GetString returns the string value for a given key from the session data. The zero value for a string ("") is returned if the key does not exist. An ErrTypeAssertionFailed error is returned if the value could not be type asserted or converted to a string.

func GetTime

func GetTime(r *http.Request, key string) (time.Time, error)

GetTime returns the time.Time value for a given key from the session data. The zero value for a time.Time object is returned if the key does not exist (this can be checked for with the time.IsZero method). An ErrTypeAssertionFailed error is returned if the value could not be type asserted or converted to a time.Time.

func Keys

func Keys(r *http.Request) ([]string, error)

Keys returns a slice of all key names present in the session data, sorted alphabetically. If the session contains no data then an empty slice will be returned.

func Manage

func Manage(engine Engine, opts ...Option) func(h http.Handler) http.Handler

Manage returns a new session manager middleware instance. The first parameter should be a valid storage engine, followed by zero or more functional options.

For example:

session.Manage(memstore.New(0))

session.Manage(memstore.New(0), session.Lifetime(14*24*time.Hour))

session.Manage(memstore.New(0),
	session.Secure(true),
	session.Persist(true),
	session.Lifetime(14*24*time.Hour),
)

The returned session manager can be used to wrap any http.Handler. It automatically loads sessions based on the HTTP request and saves session data as and when necessary.

func NewMockRequest

func NewMockRequest(r *http.Request) *http.Request

func PopBool

func PopBool(r *http.Request, key string) (bool, error)

PopBool removes the bool value for a given key from the session data and returns it. The zero value for a bool (false) is returned if the key does not exist. An ErrTypeAssertionFailed error is returned if the value could not be type asserted to a bool.

func PopBytes

func PopBytes(r *http.Request, key string) ([]byte, error)

PopBytes removes the byte slice ([]byte) value for a given key from the session data and returns it. The zero value for a slice (nil) is returned if the key does not exist. An ErrTypeAssertionFailed error is returned if the value could not be type asserted or converted to a []byte.

func PopFloat

func PopFloat(r *http.Request, key string) (float64, error)

PopFloat removes the float64 value for a given key from the session data and returns it. The zero value for an float (0) is returned if the key does not exist. An ErrTypeAssertionFailed error is returned if the value could not be type asserted or converted to a float64.

func PopInt

func PopInt(r *http.Request, key string) (int, error)

PopInt removes the int value for a given key from the session data and returns it. The zero value for an int (0) is returned if the key does not exist. An ErrTypeAssertionFailed error is returned if the value could not be type asserted or converted to a int.

func PopInt64

func PopInt64(r *http.Request, key string) (int64, error)

PopInt64 remvoes the int64 value for a given key from the session data and returns it. The zero value for an int (0) is returned if the key does not exist. An ErrTypeAssertionFailed error is returned if the value could not be type asserted or converted to a int64.

func PopObject

func PopObject(r *http.Request, key string, dst interface{}) error

PopObject removes the data for a given session key and reads it into a custom object (represented by the dst parameter). It should only be used to retrieve custom data types that have been stored using PutObject. The object represented by dst will remain unchanged if the key does not exist.

The dst parameter must be a pointer.

func PopString

func PopString(r *http.Request, key string) (string, error)

PopString removes the string value for a given key from the session data and returns it. The zero value for a string ("") is returned if the key does not exist. An ErrTypeAssertionFailed error is returned if the value could not be type asserted to a string.

func PopTime

func PopTime(r *http.Request, key string) (time.Time, error)

PopTime removes the time.Time value for a given key from the session data and returns it. The zero value for a time.Time object is returned if the key does not exist (this can be checked for with the time.IsZero method). An ErrTypeAssertionFailed error is returned if the value could not be type asserted or converted to a time.Time.

func PutBool

func PutBool(r *http.Request, key string, val bool) error

PutBool adds a bool value and corresponding key to the session data. Any existing value for the key will be replaced.

func PutBytes

func PutBytes(r *http.Request, key string, val []byte) error

PutBytes adds a byte slice ([]byte) value and corresponding key to the the session data. Any existing value for the key will be replaced.

func PutFloat

func PutFloat(r *http.Request, key string, val float64) error

PutFloat adds an float64 value and corresponding key to the session data. Any existing value for the key will be replaced.

func PutInt

func PutInt(r *http.Request, key string, val int) error

PutInt adds an int value and corresponding key to the session data. Any existing value for the key will be replaced.

func PutInt64

func PutInt64(r *http.Request, key string, val int64) error

PutInt64 adds an int64 value and corresponding key to the session data. Any existing value for the key will be replaced.

func PutObject

func PutObject(r *http.Request, key string, val interface{}) error

PutObject adds an arbitrary object and corresponding key to the the session data. Any existing value for the key will be replaced.

The val parameter must be a pointer to your object.

PutObject is typically used to store custom data types. It encodes the object into a gob and then into a base64-encoded string which is persisted by the storage engine. This makes PutObject (and the accompanying GetObject and PopObject functions) comparatively expensive operations.

Because gob encoding is used, the fields on custom types must be exported in order to be persisted correctly. Custom data types must also be registered with gob.Register before PutObject is called (see https://golang.org/pkg/encoding/gob/#Register).

Usage:

type User struct {
    Name  string
    Email string
}

func putHandler(w http.ResponseWriter, r *http.Request) {
    // Register the type with the encoding/gob package. Usually this would be
    // done in an init() function.
    gob.Register(User{})

    // Initialise a pointer to a new custom object.
    user := &User{"Alice", "alice@example.com"}

    // Store the custom object in the session data. Important: you should pass in
    // a pointer to your object, not the value.
    err := session.PutObject(r, "user", user)
    if err != nil {
        http.Error(w, err.Error(), 500)
    }
}

func PutString

func PutString(r *http.Request, key string, val string) error

PutString adds a string value and corresponding key to the the session data. Any existing value for the key will be replaced.

func PutTime

func PutTime(r *http.Request, key string, val time.Time) error

PutTime adds an time.Time value and corresponding key to the session data. Any existing value for the key will be replaced.

func RegenerateToken

func RegenerateToken(r *http.Request) error

RegenerateToken creates a new session token while retaining the current session data. The session lifetime is also reset.

The old session token and accompanying data are deleted from the storage engine.

To mitigate the risk of session fixation attacks, it's important that you call RegenerateToken before making any changes to privilege levels (e.g. login and logout operations). See https://www.owasp.org/index.php/Session_fixation for additional information.

Usage:

func loginHandler(w http.ResponseWriter, r *http.Request) {
    userID := 123

    // First regenerate the session token…
    err := session.RegenerateToken(r)
    if err != nil {
        http.Error(w, err.Error(), 500)
        return
    }

    // Then make the privilege-level change.
    err = session.PutInt(r, "userID", userID)
    if err != nil {
        http.Error(w, err.Error(), 500)
        return
    }
}

func Remove

func Remove(r *http.Request, key string) error

Remove deletes the given key and corresponding value from the session data. If the key is not present this operation is a no-op.

func Renew

func Renew(r *http.Request) error

Renew creates a new session token and removes all data for the session. The session lifetime is also reset.

The old session token and accompanying data are deleted from the storage engine.

The Renew function is essentially a concurrency-safe amalgamation of the RegenerateToken and Clear functions.

func Save

func Save(w http.ResponseWriter, r *http.Request) error

Save immediately writes the session cookie header to the ResponseWriter and saves the session data to the storage engine, if needed.

Using Save is not normally necessary. The session middleware (which buffers all writes to the underlying connection) will automatically handle setting the cookie header and storing the data for you.

However there may be instances where you wish to break out of this normal operation and (one way or another) write to the underlying connection before control is passed back to the session middleware. In these instances, where response headers have already been written, the middleware will be too late to set the cookie header. The solution is to manually call Save before performing any writes.

An example is flushing data using the http.Flusher interface:

func flushingHandler(w http.ResponseWriter, r *http.Request) {
 	err := session.PutString(r, "foo", "bar")
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}
	err = session.Save(w, r)
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}

	fw, ok := w.(http.Flusher)
	if !ok {
		http.Error(w, "could not assert to http.Flusher", 500)
		return
	}
	w.Write([]byte("This is some…"))
	fw.Flush()
	w.Write([]byte("flushed data"))
}

Types

type Engine

type Engine interface {
	// Delete should remove the session token and corresponding data from the
	// session engine. If the token does not exist then Delete should be a no-op
	// and return nil (not an error).
	Delete(token string) (err error)

	// Find should return the data for a session token from the storage engine.
	// If the session token is not found or is expired, the found return value
	// should be false (and the err return value should be nil). Similarly, tampered
	// or malformed tokens should result in a found return value of false and a
	// nil err value. The err return value should be used for system errors only.
	Find(token string) (b []byte, found bool, err error)

	// Save should add the session token and data to the storage engine, with
	// the given expiry time. If the session token already exists, then the data
	// and expiry time should be overwritten.
	Save(token string, b []byte, expiry time.Time) (err error)
}

Engine is the interface for storage engines.

type Middleware deprecated

type Middleware func(h http.Handler) http.Handler

Deprecated: Middleware previously defined the signature for the session management middleware returned by Manage. Manage now returns a func(h http.Handler) http.Handler directly instead, so it's easier to use with middleware chaining packages like Alice.

type Option

type Option func(*options)

Option defines the functional arguments for configuring the session manager.

func Domain

func Domain(s string) Option

Domain sets the 'Domain' attribute on the session cookie. By default it will be set to the domain name that the cookie was issued from.

func ErrorFunc

func ErrorFunc(f func(http.ResponseWriter, *http.Request, error)) Option

ErrorFunc allows you to control behavior when an error is encountered loading or writing a session. The default behavior is for a HTTP 500 status code to be written to the ResponseWriter along with the plain-text error string. If a custom error function is set, then control will be passed to this instead. A typical use would be to provide a function which logs the error and returns a customized HTML error page.

func HttpOnly

func HttpOnly(b bool) Option

HttpOnly sets the 'HttpOnly' attribute on the session cookie. The default value is true.

func IdleTimeout

func IdleTimeout(t time.Duration) Option

IdleTimeout sets the maximum length of time a session can be inactive before it expires. For example, some applications may wish to set this so there is a timeout after 20 minutes of inactivity. Any client request which includes the session cookie and is handled by the session middleware is classed as activity.s

By default IdleTimeout is not set and there is no inactivity timeout.

func Lifetime

func Lifetime(t time.Duration) Option

Lifetime sets the maximum length of time that a session is valid for before it expires. The lifetime is an 'absolute expiry' which is set when the session is first created and does not change.

The default value is 24 hours.

func Path

func Path(s string) Option

Path sets the 'Path' attribute on the session cookie. The default value is "/". Passing the empty string "" will result in it being set to the path that the cookie was issued from.

func Persist

func Persist(b bool) Option

Persist sets whether the session cookie should be persistent or not (i.e. whether it should be retained after a user closes their browser).

The default value is false, which means that the session cookie will be destroyed when the user closes their browser. If set to true, explicit 'Expires' and 'MaxAge' values will be added to the cookie and it will be retained by the user's browser until the given expiry time is reached.

func Secure

func Secure(b bool) Option

Secure sets the 'Secure' attribute on the session cookie. The default value is false. It's recommended that you set this to true and serve all requests over HTTPS in production environments.

Jump to

Keyboard shortcuts

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