Giter VIP home page Giter VIP logo

session's Introduction

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 https://github.com/icza/gaesession provides support for Google App Engine (GAE) platform.

The gaesession 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.

For details and examples, please visit https://github.com/icza/gaesession.

session's People

Contributors

icza avatar kazzz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

session's Issues

Proposal: Releases

Could you please add releases for stable versions of code? It will be easier to deal with vendoring in this case.

Deleting and creating a new session on the same request causes dangling?

Say I have these two functions for my framework where I need to respawn the session if someone already has session values but chose Remember Me at login. I'm trying to respawn a new session with the old attributes and a new, longer, expiration time:

// New generates a new session for the context. If a session
// already exists it will be discarded.
func New(c context.Context, options *session.SessOptions) {
	Delete(c)
	session.Add(session.NewSessionOptions(options), c.ResponseWriter())
}

// Delete the session.
func Delete(c context.Context) {
	if sess := session.Get(c.Request()); nil != sess {
		session.Remove(sess, c.ResponseWriter())
	}
}

Even tho I expect a delete and an add, the session-logger tells me one is deleted but two times shows me added. When I dump the internal sessions it still has the old (deleted) session too with it's old variables.

The following code is used in my login page (sessiondb is simply a small layer to automatise session existences checks):

if form.IsValid() {
	// If already had a session; need to migrate for remember me new session timeout
	var attrs map[string]interface{}
	if sessiondb.Exists(c) {
		attrs = sessiondb.GetAll(c)
	}
	var expiration time.Duration
	if "1" == form.Field("rememberMe").Value {
		expiration = time.Second * time.Duration(globals.RememberMeExpiration)
	} else {
		expiration = time.Second * time.Duration(globals.CookieExpiration)
	}
	sessiondb.New(c, &session.SessOptions{
		Timeout: expiration,
		Attrs:   attrs,
	})
	sessiondb.Set(c, "UserID", id)

	if referer := sessiondb.Get(c, "LoginReferer"); nil != referer {
		sessiondb.Unset(c, "LoginReferer")
		c.Redirect(referer.(string))
	} else {
		c.Redirect("/")
	}
	return
}

In the above case;

  • the old session still exists with only LoginReferer
  • the new session exists with UserID and LoginReferer, which of course is consumed again right away if it was set to jump back to where to user was before being bounced to the login page (e.a. authorised environment)

Eliminate log.Println for in-memory store add, remove and timeout ops

Hi @icza

Great package: clean, to the point, does what it advertises to be doing.

Quick question: only to avoid forking my own thing, would you consider making the log.Println operations optional for the in-memory store ?
https://github.com/icza/session/blob/master/inmem_store.go#L101
https://github.com/icza/session/blob/master/inmem_store.go#L129
https://github.com/icza/session/blob/master/inmem_store.go#L138

Maybe, to keep current logging for users that want it, have a boolean field DoNotLogEvents to the InMemStoreOptions struct and a private doNotLog to the inMemStore.
Those one could be set as needed when invoking: NewInMemStoreOptions
The log statements would be wrapped inside an if !s.doNotLog { log... }

Obviously, no pressure, I would be glad to send a pull request

Regards,
Silviu

sessionImpl.mux can be nil

Second request(reload) made runtime error in my project.

2017/03/04 03:16:12 http: panic serving 127.0.0.1:60332: runtime error: invalid memory address or nil pointer dereference
goroutine 42 [running]:
net/http.(*conn).serve.func1(0xc820244180)
/usr/local/go_appengine/goroot/src/net/http/server.go:1389 +0xc1
panic(0x93e320, 0xc82000a070)
/usr/local/go_appengine/goroot/src/runtime/panic.go:443 +0x4e9
sync.(*RWMutex).Lock(0x0)
/usr/local/go_appengine/goroot/src/sync/rwmutex.go:83 +0xc6
github.com/icza/session.(*sessionImpl).Access(0xc82004f680)
/usr/local/go_appengine/src/github.com/icza/session/session.go:227 +0x29
github.com/icza/session.(*memcacheStore).Get(0xc82024a1e0, 0xc820167427, 0x18, 0x0, 0x0)

I try to fix mux-type and related code, then problem was solved.
session.go line80
Before
mux *sync.RWMutex
After
mux sync.RWMutex

If it is bug, I hope fix.

Question: The signatures of the Store interface methods

I have a question about dealing with errors.
The signatures of the Store interface methods don't have error as return value.
What is the best way to deal with errors in this case?

For example, if I use database, in case of error I'd like to return error to the part of code which asked for the method. The Store interface methods don't give me this possibility, so the only way is to return nil and log error. But in some cases I'd like to tell user that something went wrong instead of pretending that session was saved.

For example, I want something like this:

err := session.Add(sessionData, c.Writer)
if err != nil {
  // return 500 error
}

But I have only this:

session.Add(sessionData, c.Writer)
// How can I understand that something went wrong?

Do you think if it is possible to add error to the signatures in the next major version of the library?

Async save to datastore incorrect

Go app engine doesn't allow datastore interactions after the ctx is cleared which is tied to the request lifecycle. Though it's possible the datastore interactions could occur before the context expires it's not possible to guarantee it. If you want for it to work you'll have to do something like go delay but that requires the library consumer to make some configuration changes.

Session only works...

I am not sure if it is supposed to work this way, but sessions clear when I goto a page they are not implemented on.

Example:

/search
/login (session implemented)
/user_stuff (session implemented)
/user_stuff_2 (session implemented)

If a user logs in with the session and goes to /user_stuff everything works fine.
It also works when they goto user_stuff_2 and back and forth. There is no issues it is actually pretty awesome, but I have a problem if at any point the user goes to /search where the sessions are not implemented it will clear the session and if they goto /user_stuff they will not be logged in. I have tried this a few different ways but it seems to always clear the session.
I can fix this by implementing session on the search page for kicks, but I would have a lot of pages I need to add this to.

Is this typical behavior or is it something else on my end that is acting funny?
Are there any typical work arounds?

go1.11: "appengine build tag is now deprecated"

Although it would kind of need a rewrite as all the log statements panic because:

goroutine 39 [running]:
net/http.(*conn).serve.func1(0xc00026a320)
        /usr/lib/go-1.11/src/net/http/server.go:1746 +0xd0
panic(0x889120, 0xc000090cb0)
        /usr/lib/go-1.11/src/runtime/panic.go:513 +0x1b9
google.golang.org/appengine/internal.Logf(0x9ad5c0, 0xc00006ae00, 0x3, 0x93b01b, 0x34, 0xc00000c900, 0x2, 0x2)
        /home/arran/go/pkg/mod/google.golang.org/[email protected]/internal/api_common.go:87 +0x15f
google.golang.org/appengine/log.Errorf(0x9ad5c0, 0xc00006ae00, 0x93b01b, 0x34, 0xc00000c900, 0x2, 0x2)
        /home/arran/go/pkg/mod/google.golang.org/[email protected]/log/api.go:34 +0x73
github.com/arran4/session.(*memcacheStore).setMemcacheSession(0xc00006e900, 0x9b0080, 0xc00006e960, 0xc00001eb40)
        /home/arran/go/pkg/mod/github.com/arran4/[email protected]/gae_memcache_store.go:249 +0x2c2
github.com/arran4/session.(*memcacheStore).Add(0xc00006e900, 0x9b0080, 0xc00006e960)
        /home/arran/go/pkg/mod/github.com/arran4/[email protected]/gae_memcache_store.go:227 +0x83
github.com/arran4/session.(*CookieManager).Add(0xc00006aec0, 0x9b0080, 0xc00006e960, 0x9ad100, 0xc0002420e0)
        /home/arran/go/pkg/mod/github.com/arran4/[email protected]/cookie_manager.go:101 +0x126

memcacheStore Get load logic wrong

You need to swap After to Before

if e.Expires.Before(time.Now()) {
   // Session expired.
   datastore.Delete(s.ctx, key) // Omitting error check...
   return nil
}

Effect of the current code is always to delete a valid session if the memcache is cleared.

Session data not being removed

I have a logout function which uses session.Remove(sess, res) BUT I don't believe that it is completely removing the session data because I am still able to view session data(via a user edit page which displays a logged in users data) after that function is called. Also, when a session is started I see Session added... in my terminal. Is there supposed to be a similar message for when a session ends(Session ended...)? Thank you.

If you have a moment, here is a link to my code:

https://github.com/pascalallen/Go-db/blob/master/db.go

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.