Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor v3 #35

Merged
merged 18 commits into from
Jun 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 76 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,39 +9,41 @@ Most session libraries are highly opinionated and hard-wired to work with `net/h
## 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. Pre-built redis/postgres/in-memory stores that can be separately installed.
3. Pre-built redis/postgres/in-memory/securecookie stores that can be separately installed.
4. Multiple session instances with custom handlers and different backend stores.

## Installation
Install `simplesessions` and all [available stores](/stores).

```shell
go get -u github.com/vividvilla/simplesessions
go get -u github.com/vividvilla/simplesessions/v3

# Install the requrired store: memory|goredis|redis|postgres
go get -u github.com/vividvilla/simplesessions/stores/goredis
# Install the requrired store: memory|redis|postgres|securecookie
go get -u github.com/vividvilla/simplesessions/v3/stores/redis
go get -u github.com/vividvilla/simplesessions/v3/stores/postgres
```

# Stores
Sessions can be stored to any backend by implementing the [store](/store.go) interface. The following stores are bundled.

* [in-memory](/stores/memory)
* [redis](/stores/redis)
* [postgres](/stores/postgres)
* [in-memory](/stores/memory)
* [secure cookie](/stores/securecookie)

# Usage
Check the [examples](/examples) directory for complete examples.

## Connecting a store
Stores can be registered to a session instance by using `Use` method.
Stores can be registered to a session instance by using `Use` method. Check individual [Stores](#stores) docs for more details.

```go
sess := simplesessions.New(simplesessions.Options{})
sess.UseStore(memory.New())
sess.UseStore(store.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](/examples).
Any HTTP library can be connected to simplesessions by registering the get and set cookie hooks using `SetCookieHooks()`. The below example shows a simple `net/http` usecase. Another example showing `fasthttp` can be found [here](/examples).

```go
var sessMan *simplesessions.Manager
Expand Down Expand Up @@ -81,61 +83,104 @@ func setCookie(cookie *http.Cookie, w interface{}) error {
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`
// Read interface sent to callback registered with get cookie hook
// and write interface is sent to callback registered with write cookie hook
// set using `SetCookieHooks()` method.
//
// 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.
//
// If `Options.EnableAutoCreate` is set to True then if session doesn't exist it will
// be immediately created and returned. Bydefault its set to False so if session doesn't
// exist then `ErrInvalidSession` error is returned.
sess, err := sessMan.Acquire(nil, r, w)

// If session doesn't exist then create new session.
// In a traditional login flow you can create a new session once user completes the login flow.
if err == simplesessions.ErrInvalidSession {
sess, err = sessMan.NewSession(r, w)
}

// Use 'Set` or `SetMulti` to set a field for session.
err = sess.Set("somekey", "somevalue")
err = sess.Set("someotherkey", 10)
err = sess.Commit()
err = sess.SetMulti(map[string]interface{}{
"k1": "v1",
"k2": "v2",
})

// 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"))
fmt.Println("val=", val)

// 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()
all, err := sess.GetAll()
fmt.Println("all=", all)

// 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")
vals, err := sess.GetMulti("somekey", "someotherkey")
fmt.Println("vals=", vals)

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

// Use `Clear` to empty the session but to keep the session alive.
err = sess.Clear()

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

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{})
sessMan := simplesessions.New(simplesessions.Options{
// If set to true then `Acquire()` method will create new session instead of throwing
// `ErrInvalidSession` when the session doesn't exist. By default its set to false.
EnableAutoCreate: false,
Cookie: simplesessions.CookieOptions{
// Name sets http cookie name. This is also sent as cookie name in `GetCookie` callback.
Name: "session",
// Domain sets hostname for the cookie. Domain specifies allowed hosts to receive the cookie.
Domain: "example.com",
// Path sets path for the cookie. Path indicates a URL path that must exist in the requested URL in order to send the cookie header.
Path: "/",
// IsSecure marks the cookie as secure cookie (only sent in HTTPS).
IsSecure: true,
// IsHTTPOnly marks the cookie as http only cookie. JS won't be able to access the cookie so prevents XSS attacks.
IsHTTPOnly: true,
// SameSite sets allows you to declare if your cookie should be restricted to a first-party or same-site context.
SameSite: http.SameSiteDefaultMode,
// Expires sets absolute expiration date and time for the cookie.
// If both Expires and MaxAge are sent then MaxAge takes precedence over Expires.
// Cookies without a Max-age or Expires attribute – are deleted when the current session ends
// and some browsers use session restoring when restarting. This can cause session cookies to last indefinitely.
Expires: time.Now().Add(time.Hour * 24),
// Sets the cookie's expiration in seconds from the current time, internally its rounder off to nearest seconds.
// If both Expires and MaxAge are sent then MaxAge takes precedence over Expires.
// Cookies without a Max-age or Expires attribute – are deleted when the current session ends
// and some browsers use session restoring when restarting. This can cause session cookies to last indefinitely.
MaxAge: time.Hour * 24,
},
})

// Create a new store instance and attach to session manager
sessMan.UseStore(memory.New())
// Register callbacks for read and write cookie
// 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)
sessMan.SetCookieHooks(getCookie, setCookie)

http.HandleFunc("/set", handler)
// Initialize the handler.
http.HandleFunc("/", handler)
}
```
14 changes: 0 additions & 14 deletions TODO

This file was deleted.

187 changes: 0 additions & 187 deletions conv/conv.go

This file was deleted.

Loading
Loading