在golang中实现session会话保持,用来做单一用户登陆验证
https://blog.csdn.net/qq_21852449/article/details/88093941
点击查看代码
package hsession
import (
"crypto/rand"
"encoding/base64"
"io"
"net/http"
"net/url"
"strconv"
"sync"
"time"
)
// manage all sessions in system running
type HSessionMgr struct {
hCookieName string // client cookie name
hMaxLifeTime int64 // determine whether to delete
hSessions map[string]*HSession // container for sessions
hLock sync.RWMutex // mutex
}
type HSession struct {
hSessionID string //unique key
hLastTimeAccessed time.Time
hValues map[interface{}]interface{} //store variables
}
// create a session manager
// run GC
func NewSessionMgr(cookieName string, maxLifeTime int64) *HSessionMgr {
mgr := &HSessionMgr{hCookieName: cookieName, hMaxLifeTime: maxLifeTime, hSessions: make(map[string]*HSession)}
go mgr.GC()
return mgr
}
//func NewSessionMgr(cookieName string, args []interface{}) *HSessionMgr {
// maxLifeTime :=3600
// mgr := &HSessionMgr{hCookieName: cookieName, hMaxLifeTime: maxLifeTime, hSessions: make(map[string]*HSession)}
// go mgr.GC()
// return mgr
//}
//start session at login action
func (hSessionMgr *HSessionMgr) StartSession(w http.ResponseWriter, r *http.Request) string {
hSessionMgr.hLock.Lock() // add lock
defer hSessionMgr.hLock.Unlock() // auto unlock
newSessionID := url.QueryEscape(hSessionMgr.NewSessionID()) //create new session,whether or not
sessionPoint := &HSession{hSessionID: newSessionID, hLastTimeAccessed: time.Now(), hValues: make(map[interface{}]interface{})}
hSessionMgr.hSessions[newSessionID] = sessionPoint
//set cookie
responseCookie := http.Cookie{Name: hSessionMgr.hCookieName, Value: newSessionID, Path: "/", HttpOnly: true, MaxAge: int(hSessionMgr.hMaxLifeTime)}
http.SetCookie(w, &responseCookie) // write
return newSessionID
}
//stop session 1.drop session object from memory 2.set expire cookie for web
func (hSessionMgr *HSessionMgr) StopSession(w http.ResponseWriter, r *http.Request) {
cookie, err := r.Cookie(hSessionMgr.hCookieName)
if err != nil || cookie.Value == "" { //no cookie value
return
} else { //have cookie value
hSessionMgr.hLock.Lock()
defer hSessionMgr.hLock.Unlock()
delete(hSessionMgr.hSessions, cookie.Value) //drop session's point in session' map
// set cookie timeout right now
expireTime := time.Now()
cookie := http.Cookie{Name: hSessionMgr.hCookieName, Path: "/", HttpOnly: true, Expires: expireTime, MaxAge: -1}
http.SetCookie(w, &cookie)
}
}
//manually stopping the session
func (hSessionMgr *HSessionMgr) StopSessionBySessionID(sessionID string) {
hSessionMgr.hLock.Lock()
defer hSessionMgr.hLock.Unlock()
delete(hSessionMgr.hSessions, sessionID)
}
// set values in the session
func (hSessionMgr *HSessionMgr) SetSessionInnerData(sessionID string, key interface{}, value interface{}) {
hSessionMgr.hLock.Lock()
defer hSessionMgr.hLock.Unlock()
if session, ok := hSessionMgr.hSessions[sessionID]; ok {
session.hValues[key] = value
}
}
// get values in the session
func (hSessionMgr *HSessionMgr) GetSessionInnerData(sessionID string, key interface{}) (interface{}, bool) {
hSessionMgr.hLock.Lock()
defer hSessionMgr.hLock.Unlock()
if session, ok := hSessionMgr.hSessions[sessionID]; ok {
if val, ok := session.hValues[key]; ok {
return val, ok
}
}
return nil, false
}
// get sessionID list
func (hSessionMgr HSessionMgr) GetSessionIDList() []string {
hSessionMgr.hLock.Lock()
defer hSessionMgr.hLock.Unlock()
sessionIDList := make([]string, 0)
for key, _ := range hSessionMgr.hSessions {
sessionIDList = append(sessionIDList, key)
}
return sessionIDList[0:len(sessionIDList)] //len cap
}
//validate cookie using in intercept when get request from client
func (hSessionMgr *HSessionMgr) CheckValidAndFlashTime(w http.ResponseWriter, r *http.Request) (string, bool) {
cookie, err := r.Cookie(hSessionMgr.hCookieName)
if cookie == nil || err != nil {
return "cookie is nil", false
}
hSessionMgr.hLock.Lock()
defer hSessionMgr.hLock.Unlock()
currentSessionID := cookie.Value
if session, ok := hSessionMgr.hSessions[currentSessionID]; ok { //judge if existed
session.hLastTimeAccessed = time.Now() //flash time
return currentSessionID, true
}
return "no session id in memory", false
}
// get last flash time
func (hSessionMgr *HSessionMgr) GetLastAccessedTime(sessionID string) (time.Time, bool) {
hSessionMgr.hLock.Lock()
defer hSessionMgr.hLock.Unlock()
if session, ok := hSessionMgr.hSessions[sessionID]; ok {
return session.hLastTimeAccessed, true
}
return time.Now(), false
}
func (hSessionMgr *HSessionMgr) GC() {
hSessionMgr.hLock.Lock()
defer hSessionMgr.hLock.Unlock()
for sessionID, session := range hSessionMgr.hSessions {
if session.hLastTimeAccessed.Unix()+hSessionMgr.hMaxLifeTime < time.Now().Unix() {
//uid := strconv.FormatInt(session.hValues["uid"].(int64), 10) todo 更新用户状态为离线
delete(hSessionMgr.hSessions, sessionID)
}
}
time.AfterFunc(time.Duration(hSessionMgr.hMaxLifeTime)*time.Second, func() {
hSessionMgr.GC()
})
}
// create unique key
func (hSessionMgr *HSessionMgr) NewSessionID() string {
b := make([]byte, 32)
if _, err := io.ReadFull(rand.Reader, b); err != nil {
nano := time.Now().UnixNano()
return strconv.FormatInt(nano, 10)
}
return base64.URLEncoding.EncodeToString(b)
}
func (hSessionMgr *HSessionMgr) CurrentUserID(r *http.Request) int64 {
//user := model.User{}
cookie, err := r.Cookie(hSessionMgr.hCookieName)
if cookie == nil || err != nil {
return -1
}
session := hSessionMgr.hSessions[cookie.Value]
//service.User.Get(r,uid,&user)
uid := session.hValues["uid"].(int64)
return uid
}
func (hSessionMgr *HSessionMgr) DropByUserID(uid int64) bool {
for key, session := range hSessionMgr.hSessions {
if session.hValues["uid"] == uid {
delete(hSessionMgr.hSessions, key)
return true
}
}
return false
}
var HSessionHelper *HSessionMgr //singleton pattern
写入自己的博客中才能记得长久