-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathsession.go
143 lines (124 loc) · 2.97 KB
/
session.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package sessions
import (
"github.com/gin-gonic/gin"
"github.com/go-redis/redis/v8"
uuid "github.com/satori/go.uuid"
"net/http"
"net/url"
"sync"
)
// cookiesMap store manage cookie data
var (
cookies []*cookieType
once sync.Once
)
type cookieType struct {
cookie *http.Cookie
valueType valueType
}
const (
Redis storeType = "redis"
Memory storeType = "memory"
ValueMap valueType = iota
ValueString
)
type (
// data store type
storeType string
// cookie value type
valueType int
)
// Session single cookie value object
type Session interface {
Get(keys ...string) interface{}
Set(value interface{}, keys ...string)
Delete(keys ...string)
}
// SessionMgr object manage
type SessionMgr interface {
GetSession(cookValue string) Session
CreateSession(cookValue string, valueType valueType, expire int) Session
}
func ChooseSessionStore(st storeType, clients ...*redis.Client) (mgr SessionMgr) {
if st == "" {
st = Memory
}
if st == Redis && len(clients) == 0 {
panic("need clients")
}
switch st {
case Redis:
mgr = newRedisMgr(clients[0])
case Memory:
mgr = newMemoryMgr()
default:
mgr = newMemoryMgr()
return
}
return
}
// SetCookie setting cookie
func SetCookie(valueType valueType, name string, maxAge int, path, domain string, secure, httpOnly bool) {
once.Do(func() {
cookies = make([]*cookieType, 0, 10)
})
if name == "" {
panic("cookie name can't nil")
}
for _, v := range cookies {
if v.cookie.Name == name {
panic("Please check if you have the same cookie name")
}
}
cookies = append(cookies, &cookieType{
valueType: valueType,
cookie: &http.Cookie{
Name: name,
MaxAge: maxAge,
Path: path,
Domain: domain,
Secure: secure,
HttpOnly: httpOnly,
},
})
}
// Sessions middleware of cookies
func Sessions(mgr SessionMgr) gin.HandlerFunc {
return func(ctx *gin.Context) {
if len(cookies) == 0 {
return
}
// request cookies
rCookies := ctx.Request.Cookies()
for _, cookie := range cookies {
var session Session
value := uuid.NewV4().String()
// search by request cookies
for _, rCookie := range rCookies {
if cookie.cookie.Name == rCookie.Name {
session = mgr.GetSession(rCookie.Value)
value = rCookie.Value
break
}
}
// not found
if session == nil {
session = mgr.CreateSession(value, cookie.valueType, cookie.cookie.MaxAge)
}
// set gin key value is session
ctx.Set(cookie.cookie.Name, session)
//The cookie must be set before the handler returns
ctx.SetCookie(cookie.cookie.Name, url.QueryEscape(value), cookie.cookie.MaxAge,
cookie.cookie.Path, cookie.cookie.Domain, cookie.cookie.Secure, cookie.cookie.HttpOnly)
}
// execute net gin.HandlerFuc
ctx.Next()
}
}
// GetSession Session Object
// If you use a custom plaintext cookie, use c.Cookie(name) or http.Request.Cookie(name)
// @param ctx gin.context
// @param name is cookie name
func GetSession(ctx *gin.Context, name string) Session {
return ctx.MustGet(name).(Session)
}