session

The session middleware provides user session management for Flame instances, supporting various storage backends, including memory, file, PostgreSQL, MySQL, Redis and MongoDB.

You can read source code of this middleware on GitHubsession - 图1open in new window and API documentation on pkg.go.devsession - 图2open in new window.

Installation

The minimum requirement of Go is 1.16.

  1. go get github.com/flamego/session

Storage backends

WARNING

Examples included in this section is to demonstrate the usage of the session middleware, by no means illustrates the idiomatic or even correct way of doing user authentication.

Memory

The session.Sessionersession - 图3open in new window works out-of-the-box with an optional session.Optionssession - 图4open in new window and uses memory as the storage backend:

  1. package main
  2. import (
  3. "strconv"
  4. "github.com/flamego/flamego"
  5. "github.com/flamego/session"
  6. )
  7. func main() {
  8. f := flamego.Classic()
  9. f.Use(session.Sessioner())
  10. f.Get("/set", func(s session.Session) string {
  11. s.Set("user_id", 123)
  12. return "Succeed"
  13. })
  14. f.Get("/get", func(s session.Session) string {
  15. userID, ok := s.Get("user_id").(int)
  16. if !ok || userID <= 0 {
  17. return "Not authenticated"
  18. }
  19. return "Authenticated as " + strconv.Itoa(userID)
  20. })
  21. f.Get("/clear", func(s session.Session) string {
  22. s.Delete("user_id")
  23. return "Cleared"
  24. })
  25. f.Run()
  26. }

Because the memory is volatile, session data do not survive over restarts. Choose other storage backends if you need to persist session data.

File

The session.FileInitersession - 图5open in new window is the function to initialize a file storage backend, used together with session.FileConfigsession - 图6open in new window to customize the backend:

  1. package main
  2. import (
  3. "os"
  4. "path/filepath"
  5. "strconv"
  6. "github.com/flamego/flamego"
  7. "github.com/flamego/session"
  8. )
  9. func main() {
  10. f := flamego.Classic()
  11. f.Use(session.Sessioner(
  12. session.Options{
  13. Initer: session.FileIniter(),
  14. Config: session.FileConfig{
  15. RootDir: filepath.Join(os.TempDir(), "sessions"),
  16. },
  17. },
  18. ))
  19. f.Get("/set", func(s session.Session) string {
  20. s.Set("user_id", 123)
  21. return "Succeed"
  22. })
  23. f.Get("/get", func(s session.Session) string {
  24. userID, ok := s.Get("user_id").(int)
  25. if !ok || userID <= 0 {
  26. return "Not authenticated"
  27. }
  28. return "Authenticated as " + strconv.Itoa(userID)
  29. })
  30. f.Get("/clear", func(s session.Session) string {
  31. s.Delete("user_id")
  32. return "Cleared"
  33. })
  34. f.Run()
  35. }

PostgreSQL

The postgres.Initersession - 图7open in new window is the function to initialize a PostgreSQL storage backend, used together with postgres.Configsession - 图8open in new window to customize the backend:

  1. package main
  2. import (
  3. "os"
  4. "strconv"
  5. "github.com/flamego/flamego"
  6. "github.com/flamego/session"
  7. "github.com/flamego/session/postgres"
  8. )
  9. func main() {
  10. f := flamego.Classic()
  11. dsn := os.ExpandEnv("postgres://$PGUSER:$PGPASSWORD@$PGHOST:$PGPORT/$PGDATABASE?sslmode=$PGSSLMODE")
  12. f.Use(session.Sessioner(
  13. session.Options{
  14. Initer: postgres.Initer(),
  15. Config: postgres.Config{
  16. DSN: dsn,
  17. Table: "sessions",
  18. InitTable: true,
  19. },
  20. },
  21. ))
  22. f.Get("/set", func(s session.Session) string {
  23. s.Set("user_id", 123)
  24. return "Succeed"
  25. })
  26. f.Get("/get", func(s session.Session) string {
  27. userID, ok := s.Get("user_id").(int)
  28. if !ok || userID <= 0 {
  29. return "Not authenticated"
  30. }
  31. return "Authenticated as " + strconv.Itoa(userID)
  32. })
  33. f.Get("/clear", func(s session.Session) string {
  34. s.Delete("user_id")
  35. return "Cleared"
  36. })
  37. f.Run()
  38. }

MySQL

The mysql.Initersession - 图9open in new window is the function to initialize a MySQL storage backend, used together with mysql.Configsession - 图10open in new window to customize the backend:

  1. package main
  2. import (
  3. "os"
  4. "strconv"
  5. "github.com/flamego/flamego"
  6. "github.com/flamego/session"
  7. "github.com/flamego/session/mysql"
  8. )
  9. func main() {
  10. f := flamego.Classic()
  11. dsn := os.ExpandEnv("$MYSQL_USER:$MYSQL_PASSWORD@tcp($MYSQL_HOST:$MYSQL_PORT)/$MYSQL_DATABASE?charset=utf8&parseTime=true")
  12. f.Use(session.Sessioner(
  13. session.Options{
  14. Initer: mysql.Initer(),
  15. Config: mysql.Config{
  16. DSN: dsn,
  17. Table: "cache",
  18. InitTable: true,
  19. },
  20. },
  21. ))
  22. f.Get("/set", func(s session.Session) string {
  23. s.Set("user_id", 123)
  24. return "Succeed"
  25. })
  26. f.Get("/get", func(s session.Session) string {
  27. userID, ok := s.Get("user_id").(int)
  28. if !ok || userID <= 0 {
  29. return "Not authenticated"
  30. }
  31. return "Authenticated as " + strconv.Itoa(userID)
  32. })
  33. f.Get("/clear", func(s session.Session) string {
  34. s.Delete("user_id")
  35. return "Cleared"
  36. })
  37. f.Run()
  38. }

Redis

The redis.Initersession - 图11open in new window is the function to initialize a Redis storage backend, used together with redis.Configsession - 图12open in new window to customize the backend:

  1. package main
  2. import (
  3. "os"
  4. "strconv"
  5. "github.com/flamego/flamego"
  6. "github.com/flamego/session"
  7. "github.com/flamego/session/redis"
  8. )
  9. func main() {
  10. f := flamego.Classic()
  11. f.Use(session.Sessioner(
  12. session.Options{
  13. Initer: redis.Initer(),
  14. Config: redis.Config{
  15. Options: &redis.Options{
  16. Addr: os.ExpandEnv("$REDIS_HOST:$REDIS_PORT"),
  17. DB: 15,
  18. },
  19. },
  20. },
  21. ))
  22. f.Get("/set", func(s session.Session) string {
  23. s.Set("user_id", 123)
  24. return "Succeed"
  25. })
  26. f.Get("/get", func(s session.Session) string {
  27. userID, ok := s.Get("user_id").(int)
  28. if !ok || userID <= 0 {
  29. return "Not authenticated"
  30. }
  31. return "Authenticated as " + strconv.Itoa(userID)
  32. })
  33. f.Get("/clear", func(s session.Session) string {
  34. s.Delete("user_id")
  35. return "Cleared"
  36. })
  37. f.Run()
  38. }

MongoDB

The mongo.Initersession - 图13open in new window is the function to initialize a MongoDB storage backend, used together with mongo.Configsession - 图14open in new window to customize the backend:

  1. package main
  2. import (
  3. "os"
  4. "strconv"
  5. "github.com/flamego/flamego"
  6. "github.com/flamego/session"
  7. "github.com/flamego/session/mongo"
  8. "go.mongodb.org/mongo-driver/mongo/options"
  9. )
  10. func main() {
  11. f := flamego.Classic()
  12. f.Use(session.Sessioner(
  13. session.Options{
  14. Initer: mongo.Initer(),
  15. Config: mongo.Config{
  16. Options: options.Client().ApplyURI(os.Getenv("MONGODB_URI")),
  17. Database: os.Getenv("MONGODB_DATABASE"),
  18. Collection: "cache",
  19. },
  20. },
  21. ))
  22. f.Get("/set", func(s session.Session) string {
  23. s.Set("user_id", 123)
  24. return "Succeed"
  25. })
  26. f.Get("/get", func(s session.Session) string {
  27. userID, ok := s.Get("user_id").(int)
  28. if !ok || userID <= 0 {
  29. return "Not authenticated"
  30. }
  31. return "Authenticated as " + strconv.Itoa(userID)
  32. })
  33. f.Get("/clear", func(s session.Session) string {
  34. s.Delete("user_id")
  35. return "Cleared"
  36. })
  37. f.Run()
  38. }

Flash messages

The session middleware provides a mechanism for flash messages, which are always retrieved on the next access of the same session, once and only once (i.e. flash messages get deleted upon retrievals).

A flash message could just be a string in its simplest form:

  1. package main
  2. import (
  3. "github.com/flamego/flamego"
  4. "github.com/flamego/session"
  5. )
  6. func main() {
  7. f := flamego.Classic()
  8. f.Use(session.Sessioner())
  9. f.Get("/set", func(s session.Session) string {
  10. s.SetFlash("This is a flash message")
  11. return "Succeed"
  12. })
  13. f.Get("/get", func(f session.Flash) string {
  14. s, ok := f.(string)
  15. if !ok || s == "" {
  16. return "No flash message"
  17. }
  18. return s
  19. })
  20. f.Run()
  21. }

The session.Flashsession - 图15open in new window is just the value holder of the flash message, and it could be any type that fits your application’s needs, and doesn’t even have to be the same type for different routes in the same application!

  1. package main
  2. import (
  3. "fmt"
  4. "github.com/flamego/flamego"
  5. "github.com/flamego/session"
  6. )
  7. func main() {
  8. f := flamego.Classic()
  9. f.Use(session.Sessioner())
  10. f.Get("/set-simple", func(s session.Session) string {
  11. s.SetFlash("This is a flash message")
  12. return "Succeed"
  13. })
  14. f.Get("/get-simple", func(f session.Flash) string {
  15. s, ok := f.(string)
  16. if !ok || s == "" {
  17. return "No flash message"
  18. }
  19. return s
  20. })
  21. type Flash struct {
  22. Success string
  23. Error string
  24. }
  25. f.Get("/set-complex", func(s session.Session) string {
  26. s.SetFlash(Flash{
  27. Success: "It worked!",
  28. })
  29. return "Succeed"
  30. })
  31. f.Get("/get-complex", func(f session.Flash) string {
  32. s, ok := f.(Flash)
  33. if !ok {
  34. return "No flash message"
  35. }
  36. return fmt.Sprintf("%#v", s)
  37. })
  38. f.Run()
  39. }

In the above example, we use different types of flash messages (string and Flash) for different routes and both of them work!