1
0
mirror of https://github.com/alexedwards/scs.git synced 2025-07-15 01:04:36 +02:00

[feature] Support multiple sessions

This commit is contained in:
Alex Edwards
2017-10-07 19:03:35 +02:00
parent 617cb6993e
commit dbad6751cf
6 changed files with 56 additions and 20 deletions

View File

@ -22,6 +22,7 @@ func NewManager(store Store) *Manager {
httpOnly: true, httpOnly: true,
idleTimeout: 0, idleTimeout: 0,
lifetime: 24 * time.Hour, lifetime: 24 * time.Hour,
name: "session",
path: "/", path: "/",
persist: false, persist: false,
secure: false, secure: false,
@ -64,6 +65,13 @@ func (m *Manager) Lifetime(t time.Duration) {
m.opts.lifetime = t m.opts.lifetime = t
} }
// Name sets the name of the session cookie. This name should not contain whitespace,
// commas, semicolons, backslashes, the equals sign or control characters as per
// RFC6265.
func (m *Manager) Name(s string) {
m.opts.name = s
}
// Path sets the 'Path' attribute on the session cookie. The default value is "/". // 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 // Passing the empty string "" will result in it being set to the path that the
// cookie was issued from. // cookie was issued from.
@ -101,7 +109,7 @@ func NewCookieManager(key string) *Manager {
func (m *Manager) Multi(next http.Handler) http.Handler { func (m *Manager) Multi(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := context.WithValue(r.Context(), "scs.session", m.Load(r)) ctx := context.WithValue(r.Context(), m.opts.name, m.Load(r))
next.ServeHTTP(w, r.WithContext(ctx)) next.ServeHTTP(w, r.WithContext(ctx))
}) })
} }
@ -119,7 +127,7 @@ func (m *Manager) Use(next http.Handler) http.Handler {
} }
} }
ctx := context.WithValue(r.Context(), "scs.session", session) ctx := context.WithValue(r.Context(), m.opts.name, session)
next.ServeHTTP(w, r.WithContext(ctx)) next.ServeHTTP(w, r.WithContext(ctx))
}) })
} }

View File

@ -4,9 +4,8 @@ import (
"time" "time"
) )
// CookieName changes the name of the session cookie issued to clients. Note that // Deprecated: Please use the Manager.Name() method to change the name of the
// cookie names should not contain whitespace, commas, semicolons, backslashes // session cookie.
// or control characters as per RFC6265.
var CookieName = "session" var CookieName = "session"
type options struct { type options struct {
@ -14,6 +13,7 @@ type options struct {
httpOnly bool httpOnly bool
idleTimeout time.Duration idleTimeout time.Duration
lifetime time.Duration lifetime time.Duration
name string
path string path string
persist bool persist bool
secure bool secure bool

View File

@ -133,21 +133,17 @@ func TestPersist(t *testing.T) {
} }
} }
func TestCookieName(t *testing.T) { func TestName(t *testing.T) {
oldCookieName := CookieName
CookieName = "custom_cookie_name"
manager := NewManager(newMockStore()) manager := NewManager(newMockStore())
manager.Name("foo")
_, _, cookie := testRequest(t, testPutString(manager), "") _, _, cookie := testRequest(t, testPutString(manager), "")
if strings.HasPrefix(cookie, "custom_cookie_name=") == false { if strings.HasPrefix(cookie, "foo=") == false {
t.Fatalf("got %q: expected prefix %q", cookie, "custom_cookie_name=") t.Fatalf("got %q: expected prefix %q", cookie, "foo=")
} }
_, body, _ := testRequest(t, testGetString(manager), cookie) _, body, _ := testRequest(t, testGetString(manager), cookie)
if body != "lorem ipsum" { if body != "lorem ipsum" {
t.Fatalf("got %q: expected %q", body, "lorem ipsum") t.Fatalf("got %q: expected %q", body, "lorem ipsum")
} }
CookieName = oldCookieName
} }

View File

@ -28,7 +28,7 @@ func testRequest(t *testing.T, h http.Handler, cookie string) (int, string, stri
func extractTokenFromCookie(c string) string { func extractTokenFromCookie(c string) string {
parts := strings.Split(c, ";") parts := strings.Split(c, ";")
return strings.TrimPrefix(parts[0], fmt.Sprintf("%s=", CookieName)) return strings.SplitN(parts[0], "=", 2)[1]
} }
// Test Handlers // Test Handlers

View File

@ -41,7 +41,7 @@ func newSession(store Store, opts *options) *Session {
func load(r *http.Request, store Store, opts *options) *Session { func load(r *http.Request, store Store, opts *options) *Session {
// Check to see if there is a session already in the request // Check to see if there is a session already in the request
val := r.Context().Value("scs.session") val := r.Context().Value(opts.name)
if val != nil { if val != nil {
s, ok := val.(*Session) s, ok := val.(*Session)
if !ok { if !ok {
@ -50,7 +50,7 @@ func load(r *http.Request, store Store, opts *options) *Session {
return s return s
} }
cookie, err := r.Cookie(CookieName) cookie, err := r.Cookie(opts.name)
if err == http.ErrNoCookie { if err == http.ErrNoCookie {
return newSession(store, opts) return newSession(store, opts)
} else if err != nil { } else if err != nil {
@ -122,7 +122,7 @@ func (s *Session) write(w http.ResponseWriter) error {
} }
cookie := &http.Cookie{ cookie := &http.Cookie{
Name: CookieName, Name: s.opts.name,
Value: s.token, Value: s.token,
Path: s.opts.path, Path: s.opts.path,
Domain: s.opts.domain, Domain: s.opts.domain,
@ -688,7 +688,7 @@ func (s *Session) Destroy(w http.ResponseWriter) error {
} }
cookie := &http.Cookie{ cookie := &http.Cookie{
Name: CookieName, Name: s.opts.name,
Value: "", Value: "",
Path: s.opts.path, Path: s.opts.path,
Domain: s.opts.domain, Domain: s.opts.domain,

View File

@ -93,8 +93,8 @@ func TestDestroy(t *testing.T) {
if body != "OK" { if body != "OK" {
t.Fatalf("got %q: expected %q", body, "OK") t.Fatalf("got %q: expected %q", body, "OK")
} }
if strings.HasPrefix(cookie, fmt.Sprintf("%s=;", CookieName)) == false { if strings.HasPrefix(cookie, fmt.Sprintf("%s=;", manager.opts.name)) == false {
t.Fatalf("got %q: expected prefix %q", cookie, fmt.Sprintf("%s=;", CookieName)) t.Fatalf("got %q: expected prefix %q", cookie, fmt.Sprintf("%s=;", manager.opts.name))
} }
if strings.Contains(cookie, "Expires=Thu, 01 Jan 1970 00:00:01 GMT") == false { if strings.Contains(cookie, "Expires=Thu, 01 Jan 1970 00:00:01 GMT") == false {
t.Fatalf("got %q: expected to contain %q", cookie, "Expires=Thu, 01 Jan 1970 00:00:01 GMT") t.Fatalf("got %q: expected to contain %q", cookie, "Expires=Thu, 01 Jan 1970 00:00:01 GMT")
@ -193,3 +193,35 @@ func TestLoadFailure(t *testing.T) {
t.Fatalf("got %q: expected %q", body, "forced-error\n") t.Fatalf("got %q: expected %q", body, "forced-error\n")
} }
} }
func TestMultipleSessions(t *testing.T) {
manager1 := NewManager(newMockStore())
manager1.Name("foo")
_, _, cookie1 := testRequest(t, testPutString(manager1), "")
manager2 := NewManager(newMockStore())
manager2.Name("bar")
_, _, cookie2 := testRequest(t, testPutBool(manager2), "")
_, body, _ := testRequest(t, testGetString(manager1), cookie1)
if body != "lorem ipsum" {
t.Fatalf("got %q: expected %q", body, "lorem ipsum")
}
_, body, _ = testRequest(t, testGetBool(manager2), cookie2)
if body != "true" {
t.Fatalf("got %q: expected %q", body, "true")
}
_, body, _ = testRequest(t, testGetString(manager2), cookie2)
if body != "" {
t.Fatalf("got %q: expected %q", body, "")
}
_, body, _ = testRequest(t, testGetBool(manager1), cookie1)
if body != "false" {
t.Fatalf("got %q: expected %q", body, "false")
}
}