【golang】在golang中实现session会话保持,用来做单一用户登陆验证

很多变量前面加了个h,有洁癖的小伙伴见谅,现在的版本能够实现用户单一登陆,属于内存版的简单session管理,希望有大神讲一下怎么实现一个浏览器多用户登陆情况下单一登陆限制。

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

在 Iris 使用 Session 需要使用第三方库 iris/sessions。这个库提供了一个简单而强大的 Session 管理器,使得在应用程序使用 Session 变得非常容易。 首先,需要在应用程序导入 iris/sessions 包。可以使用 go get 命令来安装它: ``` go get -u github.com/kataras/iris/sessions ``` 然后,创建一个 Session 管理器: ``` package main import ( "github.com/kataras/iris/v12" "github.com/kataras/iris/v12/sessions" ) func main() { app := iris.New() // 创建一个新的 Session 管理器 manager := sessions.New(sessions.Config{ Cookie: "myapp_session", Expires: 24 * time.Hour, AllowReclaim: true, }) // 将 Session 管理器注册到应用程序 app.Use(manager.Handler()) // ... } ``` 在上面的代码,我们创建了一个名为 manager 的 Session 管理器,并将其注册到应用程序。这将使所有的路由处理程序都能够访问 Session 对象。 现在,我们可以在路由处理程序使用 Session 了: ``` func myHandler(ctx iris.Context) { // 从会话获取一个名为 "username" 的值 username := ctx.Session().GetString("username") if username != "" { ctx.WriteString("Hello, " + username + "!") } else { ctx.WriteString("Please log in first.") } } ``` 在上面的代码,我们使用 Session 对象的 GetString 方法从 Session 获取一个名为 "username" 的值。如果该值存在,则向客户端发送一个欢迎消息,否则提示用户登录。 最后,我们还可以将值保存到 Session : ``` func loginHandler(ctx iris.Context) { username := ctx.FormValue("username") // 将用户名保存到会话 ctx.Session().Set("username", username) ctx.WriteString("Welcome, " + username + "!") } ``` 在上面的代码,我们使用 Session 对象的 Set 方法将用户名保存到 Session ,以便后续使用。 这就是在 Iris 使用 Session 的基本方法。要了解更多信息,请参阅官方文档:https://github.com/kataras/iris/tree/v12/sessions。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值