go语言网络编程之session的实现

网络编程中cookie和session是必不可少的,今天就简单说一下Go语言对session的实现 。

go语言网络编程之session的实现

文章插图
图片来源于网络
cookie,简而言之就是在本地计算机保存一些用户操作的历史信息(当然包括登录信息),并在用户再次访问该站点时浏览器通过HTTP协议将本地cookie内容发送给服务器,从而完成验证,或继续上一步操作 。
session在Web开发环境下,它的含义是指一类用来在客户端与服务器端之间保持状态的解决方案 。有时候Session也用来指这种解决方案的存储结构 。
简而言之,cookie是本地的文件,存储一下和服务器相关的内容,session的服务端存储的数据,用来和cookie相互对应,简化用户登录等,因为http都是无状态的,在用户登录后,再访问其他页面时不应该再次登录,所以可以使用cookie和session来解决,我们不可能每一次访问界面都要将用户的账号密码等信息都发送一次,这样不仅是做无用功,而且也很危险 。
下面是我用go语言实现的一个简单的session:
package mainimport ( "crypto/rand" "encoding/base64" "errors" "io" "net/http" "net/url" "strconv" "sync" "time")// SessionMgr session managertype SessionMgr struct { cookieName string mLock sync.RWMutex maxLifeTime int64 sessions map[string]*Session}// Sessiontype Session struct { sessionID string lastTime time.Time values map[interface{}]interface{}}// NewSessionMgr create session managerfunc NewSessionMgr(cookieName string, maxLifeTime int64) *SessionMgr { mgr := &SessionMgr{cookieName: cookieName, maxLifeTime: maxLifeTime, sessions: make(map[string]*Session)} go mgr.SessionGC() return mgr}// NewSession create sessionfunc (mgr *SessionMgr) NewSession(w http.ResponseWriter, r *http.Request) string { mgr.mLock.Lock() defer mgr.mLock.Unlock() newSessionID := url.QueryEscape(mgr.NewSessionID()) session := &Session{sessionID: newSessionID, lastTime: time.Now(), values: make(map[interface{}]interface{})} mgr.sessions[newSessionID] = session cookie := http.Cookie{Name: mgr.cookieName, Value: newSessionID, Path: "/", HttpOnly: true, MaxAge: int(mgr.maxLifeTime)} http.SetCookie(w, &cookie) return newSessionID}// EndSessionfunc (mgr *SessionMgr) EndSession(w http.ResponseWriter, r *http.Request) { cookie, err := r.Cookie(mgr.cookieName) if err != nil || cookie.Value =https://www.isolves.com/it/cxkf/yy/go/2019-05-08/= "" { return } mgr.mLock.Lock() defer mgr.mLock.Unlock() delete(mgr.sessions, cookie.Value) newCookie := http.Cookie{Name: mgr.cookieName, Path: "/", HttpOnly: true, Expires: time.Now(), MaxAge: -1} http.SetCookie(w, &newCookie)}// EndSessionByID end the session by session IDfunc (mgr *SessionMgr) EndSessionByID(sessionID string) { mgr.mLock.Lock() defer mgr.mLock.Unlock() delete(mgr.sessions, sessionID)}// SetSessionValue set value fo sessionfunc (mgr *SessionMgr) SetSessionValue(sessionID string, key interface{}, value interface{}) error { mgr.mLock.Lock() defer mgr.mLock.Unlock() if session, ok := mgr.sessions[sessionID]; ok { session.values[key] = value return nil } return errors.New("invalid session ID")}// GetSessionValue get value fo sessionfunc (mgr *SessionMgr) GetSessionValue(sessionID string, key interface{}) (interface{}, error) { mgr.mLock.RLock() defer mgr.mLock.RUnlock() if session, ok := mgr.sessions[sessionID]; ok { if val, ok := session.values[key]; ok { return val, nil } } return nil, errors.New("invalid session ID")}//CheckCookieValid check cookie is valid or notfunc (mgr *SessionMgr) CheckCookieValid(w http.ResponseWriter, r *http.Request) (string, error) { cookie, err := r.Cookie(mgr.cookieName) if cookie == nil || err != nil { return "", err } mgr.mLock.Lock() defer mgr.mLock.Unlock() sessionID := cookie.Value if session, ok := mgr.sessions[sessionID]; ok { session.lastTime = time.Now() return sessionID, nil } return "", errors.New("invalid session ID")}// SessionGC maintain sessionfunc (mgr *SessionMgr) SessionGC() { mgr.mLock.Lock() defer mgr.mLock.Unlock() for id, session := range mgr.sessions { if session.lastTime.Unix()+mgr.maxLifeTime < time.Now().Unix() { delete(mgr.sessions, id) } } time.AfterFunc(time.Duration(mgr.maxLifeTime)*time.Second, func() { mgr.SessionGC() })}// NewSessionID generate unique IDfunc (mgr *SessionMgr) 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)}(头条对代码的支持让人头疼,大家可以去公众号查看)
这里我们有一个session管理者和一个session结构体,我们可以创建session,而且生成全局唯一的sessionID,并且设置session的存活时间,和上一次登录的时间,同样,我们也可以摧毁一个session 。这样,当有请求过来时,我们可以根据请求中的cookie的值,找到对应的sessionID,从而找到对应的session 。就可以判断这个登录是否有效了 。


推荐阅读