-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsession.go
156 lines (128 loc) · 3.52 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
144
145
146
147
148
149
150
151
152
153
154
155
156
package hamgo
import (
"net/http"
"net/url"
"sync"
"time"
)
var sessions *sessionManager
//********** Session **********
const (
sessionCookieName = "gosessionid"
second = 1
minute = 60 * second
hour = 60 * minute
defaultSessionMaxTime = hour
confSessionMaxTime = "session_max_time"
)
type Session interface {
Set(key, value interface{}) //set session value
Get(key interface{}) interface{} //get session value
Delete(key interface{}) //delete session value
ID() string //back current sessionID
LeftTime() int64 //get this session's timeout
newID()
refreshTime()
}
type session struct {
sid string //session id
timeAccessed time.Time //last access time
value map[interface{}]interface{} //session data value
timeout int //timeout second
}
func newSession(max int) Session {
return &session{sid: uuid(32), value: map[interface{}]interface{}{}, timeAccessed: time.Now(), timeout: max}
}
func (s *session) Set(key, value interface{}) {
s.value[key] = value
}
func (s *session) Get(key interface{}) interface{} {
if v, ok := s.value[key]; ok {
return v
}
return nil
}
func (s *session) Delete(key interface{}) {
delete(s.value, key)
}
func (s *session) ID() string {
return s.sid
}
func (s *session) LeftTime() int64 {
return s.timeAccessed.Unix() + int64(s.timeout) - time.Now().Unix()
}
func (s *session) newID() {
s.sid = uuid(32)
}
func (s *session) refreshTime() {
s.timeAccessed = time.Now()
}
//********** SessionStorage **********
type sessionStorage interface {
Put(Session)
Get(string) Session
}
type memorySessionStorage struct {
lock sync.Mutex //used for lock
sessions map[string]Session //used for inner store
}
func (msp *memorySessionStorage) Put(session Session) {
msp.lock.Lock()
msp.sessions[session.ID()] = session
msp.lock.Unlock()
}
func (msp *memorySessionStorage) Get(ID string) Session {
return msp.sessions[ID]
}
//********** SessionManager **********
type sessionManager struct {
storage sessionStorage
maxlifetime int
}
func (sm *sessionManager) GetSession(r *http.Request, w http.ResponseWriter) Session {
session := sm.storage.Get(getSessionID(r))
if session == nil {
session = newSession(sm.maxlifetime)
sm.SetSession(w, session)
} else {
if session.LeftTime() < 1 {
sm.DelSession(r, w)
return nil
}
//refresh left time
session.refreshTime()
}
return session
}
func (sm *sessionManager) SetSession(w http.ResponseWriter, session Session) {
sm.storage.Put(session)
cookie := &http.Cookie{Name: sessionCookieName, Value: session.ID(), Path: "/", HttpOnly: true}
http.SetCookie(w, cookie)
}
func (sm *sessionManager) DelSession(r *http.Request, w http.ResponseWriter) {
cookie := &http.Cookie{Name: sessionCookieName, Value: getSessionID(r), Path: "/", HttpOnly: true, Expires: time.Now(), MaxAge: -1}
http.SetCookie(w, cookie)
}
func (sm *sessionManager) RefreshSession(r *http.Request, w http.ResponseWriter) {
session := sm.GetSession(r, w)
if session == nil {
return
}
session.newID()
sm.SetSession(w, session)
}
//********** Tool **********
func getSessionID(r *http.Request) string {
cookie, err := r.Cookie(sessionCookieName)
if err != nil {
return ""
}
id, err := url.QueryUnescape(cookie.Value)
if err != nil {
return ""
}
return id
}
func setSession(max int) {
sessions = &sessionManager{&memorySessionStorage{sessions: map[string]Session{}}, max}
}