simplesessions

package module
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Feb 4, 2021 License: MIT Imports: 7 Imported by: 9

README

simplesessions

simplesessions is a "pure" Go session library that is completely agnostic of HTTP libraries and frameworks, backend stores, and even cookie jars.

Why?

Most session libraries are highly opinionated and hard-wired to work with net/http handlers (or other 3rd party libraries like fasthttp) and take liberties on how session data should be encoded and stored. simplesessions takes a pragmatic approach, where everything from HTTP request and cookie handling to data encoding and session storage are plugged in as simple callback functions. Moreover, most session libraries treat data as strings losing type information. simplessions provides a way to maintain primitive types such as int, string etc.

Features

  1. Framework/network library agnostic.
  2. Simple API and with support for primitive data types. Complex types can be stored using own encoding/decoding.
  3. Bundled Redis and in-memory stores.
  4. Multiple session instances with custom handlers and different backend stores.

Installation

Install simplesessions and all available stores.

go get -u github.com/vividvilla/simplesessions
go get -u github.com/vividvilla/simplesessions/stores/...

Stores

Sessions can be stored to any backend by implementing the store interface. The following stores are bundled.

Usage

Check the examples directory for complete examples.

Connecting a store

Stores can be registered to a session instance by using Use method.

sess := simplesessions.New(simplesessions.Options{})
sess.UseStore(memory.New())

Connecting an HTTP handler

Any HTTP library can be connected to simplesessions by registering the RegisterGetCookie() and RegisterSetCookie() callbacks. The below example shows a simple net/http usecase. Another example showing fasthttp can be found here.

var sessMan *simplesessions.Manager

func getCookie(name string, r interface{}) (*http.Cookie, error) {
	// Get read interface registered using `Acquire` method in handlers.
	rd := r.(*http.Request)

	// Send cookie for received cookie name from request.
	// Note that other networking libs and frameworks should
	// also send back cookie in net/http cookie format.
	// If cookie is not found for given cookie name then
	// `http.ErrNoCookie` should be returned.
	// Cookie name is what you set while creating session manager
	// with custom options (`Options.CookieName`). Defaults to `session`.
	cookie, err := rd.Cookie(name)
	if err != nil {
		return nil, err
	}

	return cookie, nil
}

func setCookie(cookie *http.Cookie, w interface{}) error {
	// Get write interface registered using `Acquire` method in handlers.
	wr := w.(http.ResponseWriter)

	// net/http cookie is returned which can be
	// used to set cookie for current request.
	// Note that other network libraries or
	// framework will also receive cookie as
	// net/http cookie and it has to set cookie accordingly.
	http.SetCookie(wr, cookie)
	return nil
}

func handler(w http.ResponseWriter, r *http.Request) {
	// Use method `Acquire` to acquire a session before you access the session.
	// Acquire takes read, write interface and context respectively.
	// Read interface sent to callback registered with `RegisterGetCookie`
	// and write interface is sent to callback registered with `RegisterWriteCookie`
	// Optionally `context` can be sent which is usually request context where acquire
	// session will get previously loaded session. This is useful if you have multiple
	// middlewares accessing sessions. New sessions will be created in first middleware which
	// does `Acquire` and will be reused in other places.
	sess, err := sessMan.Acquire(r, w, nil)

	// Use 'Set` and `Commit` to set a field for session.
	// 'Set` ideally doesn't persist the value to store unless method `Commit` is called.
	// But note that its up to the store you are using to decide to
	// persist data only on `commit` or persist on `Set` itself.
	// Stores like redis, db etc should persist on `Commit` while in-memory does on `Set`.
	// No matter what store you use its better to explicitly
	// call `Commit` method when you set all the values.
	err = sess.Set("somekey", "somevalue")
	err = sess.Set("someotherkey", 10)
	err = sess.Commit()

	// Use `Get` method to get a field from current session. The result will be an interface
	// so you can use helper methods like
	// `String', `Int`, `Int64`, `UInt64`, `Float64`, `Bytes`, `Bool`.
	val, err := sess.String(sess.Get("somekey"))

	// Use `GetAll` to get map of all fields from session.
	// The result is map of string and interface you can use helper methods to type cast it.
	val, err := sess.GetAll()

	// Use `GetMulti` to get values for given fields from session.
	// The result is map of string and interface you can use helper methods to type cast it.
	// If key is not there then store should ideally send `nil` value for given key.
	val, err := sess.GetMulti("somekey", "someotherkey")

	// Use `Delete` to delete a field from session.
	err := sess.Delete("somekey")

	// Use `Clear` to clear session from store.
	err := sess.Clear()

	fmt.Fprintf(w, "success")
}

func main() {
	// Create a session manager with custom options like cookie name,
	// cookie domain, is secure cookie etc. Check `Options` struct for more options.
	sessMan := simplesessions.New(simplesessions.Options{})
	// Create a new store instance and attach to session manager
	sessMan.UseStore(memory.New())
	// Register callbacks for read and write cookie
	// Get cookie callback should get cookie based on cookie name and
	// sent back in net/http cookie format.
	sessMan.RegisterGetCookie(getCookie)
	// Set cookie callback should set cookie it received for received cookie name.
	sessMan.RegisterSetCookie(setCookie)

	http.HandleFunc("/set", handler)
}

Documentation

Index

Constants

View Source
const (

	// ContextName is the key used to store session in context passed to acquire method.
	ContextName = "_simple_session"
)

Variables

View Source
var (
	// ErrInvalidSession is raised when session is tried to access before setting it or its not set in store.
	// Handle this and create new session.
	ErrInvalidSession = errors.New("simplesession: invalid session")
	// ErrFieldNotFound is raised when given key is not found in store
	ErrFieldNotFound = errors.New("simplesession: session field not found in store")
	// ErrAssertType is raised when type assertion fails
	ErrAssertType = errors.New("simplesession: invalid type assertion")
	// ErrNil is raised when returned value is nil.
	ErrNil = errors.New("simplesession: nil returned")
)

Functions

This section is empty.

Types

type Manager

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

Manager is a utility to scaffold session and store.

func New

func New(opts Options) *Manager

New creates a new session manager for given options.

func (*Manager) Acquire

func (m *Manager) Acquire(r, w interface{}, c context.Context) (*Session, error)

Acquire gets a `Session` for current session cookie from store. If `Session` is not found on store then it creates a new session and sets on store. If 'DisableAutoSet` is set in options then session has to be explicitly created before using `Session` for getting or setting. `r` and `w` is request and response interfaces which are sent back in GetCookie and SetCookie callbacks respectively. In case of net/http `r` will be r` Optionally context can be passed around which is used to get already loaded session. This is useful when handler is wrapped with multiple middlewares and `Acquire` is already called in any of the middleware.

func (*Manager) RegisterGetCookie

func (m *Manager) RegisterGetCookie(cb func(string, interface{}) (*http.Cookie, error))

RegisterGetCookie sets a callback to get http cookie from any reader interface which is sent on session acquisition using `Acquire` method.

func (*Manager) RegisterSetCookie

func (m *Manager) RegisterSetCookie(cb func(*http.Cookie, interface{}) error)

RegisterSetCookie sets a callback to set cookie from http writer interface which is sent on session acquisition using `Acquire` method.

func (*Manager) UseStore

func (m *Manager) UseStore(str Store)

UseStore sets the session store to be used.

type Options

type Options struct {
	// DisableAutoSet skips creation of session cookie in frontend and new session in store if session is not already set.
	DisableAutoSet bool

	// CookieName sets http cookie name. This is also sent as cookie name in `GetCookie` callback.
	CookieName string

	// CookieDomain sets hostname for the cookie. Domain specifies allowed hosts to receive the cookie.
	CookieDomain string

	// CookiePath sets path for the cookie. Path indicates a URL path that must exist in the requested URL in order to send the cookie header.
	CookiePath string

	// IsSecureCookie marks the cookie as secure cookie (only sent in HTTPS).
	IsSecureCookie bool

	// IsHTTPOnlyCookie marks the cookie as http only cookie. JS won't be able to access the cookie so prevents XSS attacks.
	IsHTTPOnlyCookie bool

	// CookieLifeTime sets expiry time for cookie.
	// If expiry time is not specified then cookie is set as session cookie which is cleared on browser close.
	CookieLifetime time.Duration

	// SameSite sets allows you to declare if your cookie should be restricted to a first-party or same-site context.
	SameSite http.SameSite
}

Options are available options to configure Manager.

type Session

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

Session is utility for get, set or clear session.

func NewSession

func NewSession(m *Manager, r, w interface{}) (*Session, error)

NewSession creates a new session. Reads cookie info from `GetCookie“ callback and validate the session with current store. If cookie not set then it creates new session and calls `SetCookie“ callback. If `DisableAutoSet` is set then it skips new session creation and should be manually done using `Create` method. If a cookie is found but its invalid in store then `ErrInvalidSession` error is returned.

func (*Session) Bool

func (s *Session) Bool(r interface{}, err error) (bool, error)

Bool is a helper to get values as Bool

func (*Session) Bytes

func (s *Session) Bytes(r interface{}, err error) ([]byte, error)

Bytes is a helper to get values as Bytes

func (*Session) Clear

func (s *Session) Clear() error

Clear clears session data from store and clears the cookie

func (*Session) Commit

func (s *Session) Commit() error

Commit commits all set to store. Its up to store to commit all previously set values at once or store it on each set.

func (*Session) Create added in v0.0.2

func (s *Session) Create() error

Create a new session. This is implicit when option `DisableAutoSet` is false else session has to be manually created before setting or getting values.

func (*Session) Delete

func (s *Session) Delete(key string) error

Delete deletes a field from session.

func (*Session) Float64

func (s *Session) Float64(r interface{}, err error) (float64, error)

Float64 is a helper to get values as Float64

func (*Session) GenerateRandomString

func (s *Session) GenerateRandomString(n int) (string, error)

GenerateRandomString is a utility method which can be used by store to generate cryptographically random alphanumeric string of length n.

func (*Session) Get

func (s *Session) Get(key string) (interface{}, error)

Get gets a value for given key in session. If session is already loaded using `Load` then returns values from existing map instead of getting it from store.

func (*Session) GetAll

func (s *Session) GetAll() (map[string]interface{}, error)

GetAll gets all the fields in the session.

func (*Session) GetMulti

func (s *Session) GetMulti(keys ...string) (map[string]interface{}, error)

GetMulti gets a map of values for multiple session keys.

func (*Session) ID added in v0.1.0

func (s *Session) ID() string

ID returns the acquired session ID. If cookie is not set then empty string is returned.

func (*Session) Int

func (s *Session) Int(r interface{}, err error) (int, error)

Int is a helper to get values as integer

func (*Session) Int64

func (s *Session) Int64(r interface{}, err error) (int64, error)

Int64 is a helper to get values as Int64

func (*Session) IsValidRandomString

func (s *Session) IsValidRandomString(val string) bool

IsValidRandomString validates the random string generated by `GenerateRandomString` method.

func (*Session) LoadValues

func (s *Session) LoadValues() error

LoadValues loads the session values in memory. Get session field tries to get value from memory before hitting store.

func (*Session) ResetValues

func (s *Session) ResetValues()

ResetValues reset the loaded values using `LoadValues` method.ResetValues Subsequent Get, GetAll and GetMulti

func (*Session) Set

func (s *Session) Set(key string, val interface{}) error

Set sets a value for given key in session. Its up to store to commit all previously set values at once or store it on each set.

func (*Session) String

func (s *Session) String(r interface{}, err error) (string, error)

String is a helper to get values as String

func (*Session) UInt64

func (s *Session) UInt64(r interface{}, err error) (uint64, error)

UInt64 is a helper to get values as UInt64

func (*Session) WriteCookie

func (s *Session) WriteCookie(cv string) error

WriteCookie updates the cookie and calls `SetCookie` callback. This method can also be used by store to update cookie whenever the cookie value changes.

type Store

type Store interface {
	// IsExist checks if session is set in store.
	IsValid(session *Session, cookieValue string) (isExist bool, err error)

	// Create creates new session in store and returns the cookie value.
	Create(session *Session) (cookieValue string, err error)

	// Get gets a value for given key from session.
	Get(session *Session, cookieValue, key string) (value interface{}, err error)

	// GetMulti gets a maps of multiple values for given keys.
	GetMulti(session *Session, cookieValue string, keys ...string) (values map[string]interface{}, err error)

	// GetAll gets all key and value from session,
	GetAll(session *Session, cookieValue string) (values map[string]interface{}, err error)

	// Set sets an value for a field in session.
	// Its up to store to either store it in session right after set or after commit.
	Set(session *Session, cookieValue, key string, value interface{}) error

	// Commit commits all the previously set values to store.
	Commit(session *Session, cookieValue string) error

	// Delete a field from session.
	Delete(session *Session, cookieValue string, key string) error

	// Clear clears the session key from backend if exists.
	Clear(session *Session, cookieValue string) error

	// Helper method for typecasting/asserting.
	Int(interface{}, error) (int, error)
	Int64(interface{}, error) (int64, error)
	UInt64(interface{}, error) (uint64, error)
	Float64(interface{}, error) (float64, error)
	String(interface{}, error) (string, error)
	Bytes(interface{}, error) ([]byte, error)
	Bool(interface{}, error) (bool, error)
}

Store represents store interface. This interface can be implemented to create various backend stores for session.

Directories

Path Synopsis
Package conv to help type assertions and conversions.
Package conv to help type assertions and conversions.
examples
nethttp-redis Module
stores
memory Module
redis Module
securecookie Module

Jump to

Keyboard shortcuts

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