在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
posted @ 2022-03-07 23:47  ty1539  阅读(407)  评论(0编辑  收藏  举报