Session Extension
Session is a special object created by the server to hold user’s state.
Hertz also provides an implementation of Session, which references Gin’s implementation.
Install
Download and install
go get github.com/hertz-contrib/sessions
Import into your code
import "github.com/hertz-contrib/sessions"
Example
package main
import (
"context"
"github.com/cloudwego/hertz/pkg/app"
"github.com/cloudwego/hertz/pkg/app/server"
"github.com/cloudwego/hertz/pkg/common/utils"
"github.com/hertz-contrib/sessions"
"github.com/hertz-contrib/sessions/cookie"
)
func main() {
h := server.New(server.WithHostPorts(":8000"))
store := cookie.NewStore([]byte("secret"))
h.Use(sessions.New("mysession", store))
h.GET("/incr", func(ctx context.Context, c *app.RequestContext) {
session := sessions.Default(c)
var count int
v := session.Get("count")
if v != nil {
count = v.(int)
count++
}
session.Set("count", count)
_ = session.Save()
c.JSON(200, utils.H{"count": count})
})
h.Spin()
}
Config
Hertz can configure the Session for a series of operations by using middleware.
The Session
interface defines the main methods to configure the Session operation.
The introduction of the interface methods is as follows:
Note: Session Wraps thinly gorilla-session methods.
Method | Function Signatures | Description |
---|---|---|
ID | ID() string | Used to fetch the Session ID generated by stores, it should not be used for user data. |
Get | Get(key interface{}) interface{} | Used to get the session value associated to the given key. |
Set | Set(key, val interface{}) | Used to set the session value associated to the given key. |
Delete | Delete(key interface{}) | Used to remove the session value associated to the given key. |
Clear | Clear() | Used to delete all values in the session. |
AddFlash | AddFlash(value interface{}, vars ...string) | Used to add a flash message to the session. |
Flashes | Flashes(vars ...string) []interface{} | Used to get a slice of flash messages from the session. |
Options | Options(Options) | Used to set configuration for a session. |
Save | Save() error | Used to save all sessions used during the current request. |
NewStore
The sessions
middleware provides NewStore
to store sessions in Cookie or Redis.
Cookie
Function signatures of cookie.NewStore
:
func NewStore(keyPairs ...[]byte) Store
Sample Code:
package main
import (
"context"
"github.com/cloudwego/hertz/pkg/app"
"github.com/cloudwego/hertz/pkg/app/server"
"github.com/cloudwego/hertz/pkg/common/utils"
"github.com/hertz-contrib/sessions"
"github.com/hertz-contrib/sessions/cookie"
)
func main() {
h := server.New(server.WithHostPorts(":8000"))
store := cookie.NewStore([]byte("secret"))
h.Use(sessions.New("mysession", store))
h.GET("/incr", func(ctx context.Context, c *app.RequestContext) {
session := sessions.Default(c)
var count int
v := session.Get("count")
if v == nil {
count = 0
} else {
count = v.(int)
count++
}
session.Set("count", count)
_ = session.Save()
c.JSON(200, utils.H{"count": count})
})
h.Spin()
}
Redis
Function signatures of redis.NewStore
:
func NewStore(size int, network, addr, passwd string, keyPairs ...[]byte) (Store, error)
Sample Code:
package main
import (
"context"
"github.com/cloudwego/hertz/pkg/app"
"github.com/cloudwego/hertz/pkg/app/server"
"github.com/cloudwego/hertz/pkg/common/utils"
"github.com/hertz-contrib/sessions"
"github.com/hertz-contrib/sessions/redis"
)
func main() {
h := server.Default(server.WithHostPorts(":8000"))
store, _ := redis.NewStore(10, "tcp", "localhost:6379", "", []byte("secret"))
h.Use(sessions.New("mysession", store))
h.GET("/incr", func(ctx context.Context, c *app.RequestContext) {
session := sessions.Default(c)
var count int
v := session.Get("count")
if v == nil {
count = 0
} else {
count = v.(int)
count++
}
session.Set("count", count)
session.Save()
c.JSON(200, utils.H{"count": count})
})
h.Spin()
}
New
The sessions
middleware provides New
to create a single Session.
Function signatures:
func New(name string, store Store) app.HandlerFunc
Sample Code:
package main
import (
"context"
"github.com/cloudwego/hertz/pkg/app"
"github.com/cloudwego/hertz/pkg/app/server"
"github.com/cloudwego/hertz/pkg/common/utils"
"github.com/hertz-contrib/sessions"
"github.com/hertz-contrib/sessions/cookie"
)
func main() {
h := server.New(server.WithHostPorts(":8000"))
store := cookie.NewStore([]byte("secret"))
h.Use(sessions.New("mysession", store))
h.GET("/hello", func(ctx context.Context, c *app.RequestContext) {
session := sessions.Default(c)
if session.Get("hello") != "world" {
session.Set("hello", "world")
_ = session.Save()
}
c.JSON(200, utils.H{"hello": session.Get("hello")})
})
h.Spin()
}
Many
The sessions
middleware provides Many
to create multiple sessions.
Function signatures:
func Many(names []string, store Store) app.HandlerFunc
Sample Code:
package main
import (
"context"
"github.com/cloudwego/hertz/pkg/app"
"github.com/cloudwego/hertz/pkg/app/server"
"github.com/cloudwego/hertz/pkg/common/utils"
"github.com/hertz-contrib/sessions"
"github.com/hertz-contrib/sessions/cookie"
)
func main() {
h := server.New(server.WithHostPorts(":8000"))
store := cookie.NewStore([]byte("secret"))
sessionNames := []string{"a", "b"}
h.Use(sessions.Many(sessionNames, store))
h.GET("/hello", func(ctx context.Context, c *app.RequestContext) {
sessionA := sessions.DefaultMany(c, "a")
sessionB := sessions.DefaultMany(c, "b")
if sessionA.Get("hello") != "world!" {
sessionA.Set("hello", "world!")
_ = sessionA.Save()
}
if sessionB.Get("hello") != "world?" {
sessionB.Set("hello", "world?")
_ = sessionB.Save()
}
c.JSON(200, utils.H{
"a": sessionA.Get("hello"),
"b": sessionB.Get("hello"),
})
})
h.Spin()
}
Default
The sessions
middleware provides Default
to fetch a single Session.
Function signatures:
func Default(c *app.RequestContext) Session
Sample Code:
package main
import (
"context"
"github.com/cloudwego/hertz/pkg/app"
"github.com/cloudwego/hertz/pkg/app/server"
"github.com/cloudwego/hertz/pkg/common/utils"
"github.com/hertz-contrib/sessions"
"github.com/hertz-contrib/sessions/cookie"
)
func main() {
h := server.New(server.WithHostPorts(":8000"))
store := cookie.NewStore([]byte("secret"))
h.Use(sessions.New("mysession", store))
h.GET("/hello", func(ctx context.Context, c *app.RequestContext) {
session := sessions.Default(c)
if session.Get("hello") != "world" {
session.Set("hello", "world")
_ = session.Save()
}
c.JSON(200, utils.H{"hello": session.Get("hello")})
})
h.Spin()
}
DefaultMany
The sessions
middleware provides DefaultMany
to get the Session based on its name.
Function signatures:
func DefaultMany(c *app.RequestContext, name string) Session
Sample Code:
package main
import (
"context"
"github.com/cloudwego/hertz/pkg/app"
"github.com/cloudwego/hertz/pkg/app/server"
"github.com/cloudwego/hertz/pkg/common/utils"
"github.com/hertz-contrib/sessions"
"github.com/hertz-contrib/sessions/cookie"
)
func main() {
h := server.New(server.WithHostPorts(":8000"))
store := cookie.NewStore([]byte("secret"))
sessionNames := []string{"a", "b"}
h.Use(sessions.Many(sessionNames, store))
h.GET("/hello", func(ctx context.Context, c *app.RequestContext) {
sessionA := sessions.DefaultMany(c, "a")
sessionB := sessions.DefaultMany(c, "b")
if sessionA.Get("hello") != "world!" {
sessionA.Set("hello", "world!")
_ = sessionA.Save()
}
if sessionB.Get("hello") != "world?" {
sessionB.Set("hello", "world?")
_ = sessionB.Save()
}
c.JSON(200, utils.H{
"a": sessionA.Get("hello"),
"b": sessionB.Get("hello"),
})
})
h.Spin()
}
Distributed Session
Hertz also provides a bizdemo for distributed session solution based on Redis.
Note: This demo is only a simple demonstration of the distributed session, the specific business code needs to be modified by the user combined with the corresponding business logic
The distributed session solution based on redis is to store the sessions of different servers in redis or redis cluster, which aims to solve the problem that the sessions of multiple servers are not synchronized in the case of distributed system.
Display of core code
- Initialize session middleware:
// biz/mw/session.go
func InitSession(h *server.Hertz) {
store, err := redis.NewStore(consts.MaxIdleNum, consts.TCP, consts.RedisAddr, consts.RedisPasswd, []byte(consts.SessionSecretKey))
if err != nil {
panic(err)
}
h.Use(sessions.New(consts.HertzSession, store))
}
- Store the session after user sign in:
// biz/handler/user/user_service.go/Login
// ...
session := sessions.Default(c)
session.Set(consts.Username, req.Username)
_ = session.Save()
// ...
- When the user visits the home page directly, determine whether the corresponding Session exists, and if not, then redirect to the login page (in this example) or restricts the resources that can be browsed or used after login:
// pkg/render/render.go
// ...
session := sessions.Default(c)
username := session.Get(consts.Username)
if username == nil {
// ...
c.Redirect(http.StatusMovedPermanently, []byte("/login.html"))
return
}
// ...
- Clear the session after user sign out:
// biz/handler/user/user_service.go/Logout
// ...
session := sessions.Default(c)
session.Delete(consts.Username)
_ = session.Save()
// ...
Session middleware encapsulates most of the complex logic, users only need to call the simple interfaces to complete the corresponding business process.
Full Example
As for usage, you may refer to example and hertz_session