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:
12
manager.go
12
manager.go
@ -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))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
|
@ -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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user