Go实现Session
type Session interface {
Set(key, value interface{})
Get(key interface{}) interface{}
Remove(key interface{}) error
GetId() string
}
type SessionFromMemory struct {
sid string
lock sync.Mutex
lastAccessedTime time.Time
maxAge int64
data map[interface{}]interface{}
}
func newSessionFromMemory() *SessionFromMemory {
return &SessionFromMemory{
data: make(map[interface{}]interface{}),
maxAge: 60 * 30,
}
}
func (si *SessionFromMemory) Set(key, value interface{}) {
si.lock.Lock()
defer si.lock.Unlock()
si.data[key] = value
}
func (si *SessionFromMemory) Get(key interface{}) interface{} {
if value := si.data[key]; value != nil {
return value
}
return nil
}
func (si *SessionFromMemory) Remove(key interface{}) error {
if value := si.data[key]; value != nil {
delete(si.data, key)
}
return nil
}
func (si *SessionFromMemory) GetId() string {
return si.sid
}
type Storage interface {
InitSession(sid string, maxAge int64) (Session, error)
SetSession(session Session) error
DestroySession(sid string) error
GCSession()
}
type FromMemory struct {
lock sync.Mutex
sessions map[string]Session
}
func newFromMemory() *FromMemory {
return &FromMemory{
sessions: make(map[string]Session, 0),
}
}
func (fm *FromMemory) InitSession(sid string, maxAge int64) (Session, error) {
fm.lock.Lock()
defer fm.lock.Unlock()
newSession := newSessionFromMemory()
newSession.sid = sid
if maxAge != 0 {
newSession.maxAge = maxAge
}
newSession.lastAccessedTime = time.Now()
fm.sessions[sid] = newSession
return newSession, nil
}
func (fm *FromMemory) SetSession(session Session) error {
fm.sessions[session.GetId()] = session
return nil
}
func (fm *FromMemory) DestroySession(sid string) error {
if _, ok := fm.sessions[sid]; ok {
delete(fm.sessions, sid)
return nil
}
return nil
}
func (fm *FromMemory) GCSession() {
sessions := fm.sessions
if len(sessions) < 1 {
return
}
for k, v := range sessions {
t := (v.(*SessionFromMemory).lastAccessedTime.Unix()) + (v.(*SessionFromMemory).maxAge)
if t < time.Now().Unix() {
fmt.Println("timeout-------->", v)
delete(fm.sessions, k)
}
}
}
type SessionManager struct {
cookieName string
storage Storage
maxAge int64
lock sync.Mutex
}
func NewSessionManager() *SessionManager {
sessionManager := &SessionManager{
cookieName: "lzy-cookie",
storage: newFromMemory(),
maxAge: 60 * 30,
}
go sessionManager.GC()
return sessionManager
}
func (m *SessionManager) GetCookieN() string {
return m.cookieName
}
func (m *SessionManager) BeginSession(w http.ResponseWriter, r *http.Request) Session {
m.lock.Lock()
defer m.lock.Unlock()
cookie, err := r.Cookie(m.cookieName)
if err != nil || cookie.Value == "" {
fmt.Println("-----------> current session not exists")
sid := m.randomId()
session, _ := m.storage.InitSession(sid, m.maxAge)
maxAge := m.maxAge
if maxAge == 0 {
maxAge = session.(*SessionFromMemory).maxAge
}
cookie := http.Cookie{
Name: m.cookieName,
Value: url.QueryEscape(sid),
Path: "/",
HttpOnly: true,
MaxAge: int(maxAge),
Expires: time.Now().Add(time.Duration(maxAge)),
}
http.SetCookie(w, &cookie)
return session
} else {
sid, _ := url.QueryUnescape(cookie.Value)
session := m.storage.(*FromMemory).sessions[sid]
fmt.Println("session --------->", session)
if session == nil {
fmt.Println("-----------> current session is nil")
newSession, _ := m.storage.InitSession(sid, m.maxAge)
maxAge := m.maxAge
if maxAge == 0 {
maxAge = newSession.(*SessionFromMemory).maxAge
}
newCookie := http.Cookie{
Name: m.cookieName,
Value: url.QueryEscape(sid),
Path: "/",
HttpOnly: true,
MaxAge: int(maxAge),
Expires: time.Now().Add(time.Duration(maxAge)),
}
http.SetCookie(w, &newCookie)
return newSession
}
fmt.Println("-----------> current session exists")
return session
}
}
func (m *SessionManager) Update(w http.ResponseWriter, r *http.Request) {
m.lock.Lock()
defer m.lock.Unlock()
cookie, err := r.Cookie(m.cookieName)
if err != nil {
return
}
t := time.Now()
sid, _ := url.QueryUnescape(cookie.Value)
sessions := m.storage.(*FromMemory).sessions
session := sessions[sid].(*SessionFromMemory)
session.lastAccessedTime = t
sessions[sid] = session
if m.maxAge != 0 {
cookie.MaxAge = int(m.maxAge)
} else {
cookie.MaxAge = int(session.maxAge)
}
http.SetCookie(w, cookie)
}
func (m *SessionManager) GetSessionById(sid string) Session {
session := m.storage.(*FromMemory).sessions[sid]
return session
}
func (m *SessionManager) MemoryIsExists(sid string) bool {
_, ok := m.storage.(*FromMemory).sessions[sid]
if ok {
return true
}
return false
}
func (m *SessionManager) Destroy(w http.ResponseWriter, r *http.Request) {
cookie, err := r.Cookie(m.cookieName)
if err != nil || cookie.Value == "" {
return
} else {
m.lock.Lock()
defer m.lock.Unlock()
sid, _ := url.QueryUnescape(cookie.Value)
m.storage.DestroySession(sid)
cookie2 := http.Cookie{
MaxAge: 0,
Name: m.cookieName,
Value: "",
Path: "/",
Expires: time.Now().Add(time.Duration(0)),
}
http.SetCookie(w, &cookie2)
}
}
func (m *SessionManager) CookieIsExists(r *http.Request) bool {
_, err := r.Cookie(m.cookieName)
if err != nil {
return false
}
return true
}
func (m *SessionManager) GC() {
m.lock.Lock()
defer m.lock.Unlock()
m.storage.GCSession()
time.AfterFunc(time.Duration(m.maxAge*10), func() {
m.GC()
})
}
func (m *SessionManager) IsFromMemory() {
m.storage = newFromMemory()
}
func (m *SessionManager) IsFromDB() {
}
func (m *SessionManager) SetMaxAge(t int64) {
m.maxAge = t
}
func (m *SessionManager) SetSessionFrom(storage Storage) {
m.storage = storage
}
func (m *SessionManager) randomId() string {
b := make([]byte, 32)
if _, err := io.ReadFull(rand.Reader, b); err != nil {
return ""
}
return base64.URLEncoding.EncodeToString(b)
}