zoukankan      html  css  js  c++  java
  • Golang的session管理器

    对于一些需要对用户进行管理(比如验证操作的权限等)的站点来说,session管理器是必不可少的。下面实现了一个线程安全的简单session管理类。
    生产环境:golang1.4.2+win7x64
    golang1.4.2+centos6.5×64

    1.代码如下:

    package Helper
    
    import (
        "crypto/rand"
        "encoding/base64"
        "io"
        "net/http"
        "net/url"
        "strconv"
        "sync"
        "time"
    )
    
    /*Session会话管理*/
    type SessionMgr struct {
        mCookieName  string       //客户端cookie名称
        mLock        sync.RWMutex //互斥(保证线程安全)
        mMaxLifeTime int64        //垃圾回收时间
    
        mSessions map[string]*Session //保存session的指针[sessionID] = session
    }
    
    //创建会话管理器(cookieName:在浏览器中cookie的名字;maxLifeTime:最长生命周期)
    func NewSessionMgr(cookieName string, maxLifeTime int64) *SessionMgr {
        mgr := &SessionMgr{mCookieName: cookieName, mMaxLifeTime: maxLifeTime, mSessions: make(map[string]*Session)}
    
        //启动定时回收
        go mgr.GC()
    
        return mgr
    }
    
    //在开始页面登陆页面,开始Session
    func (mgr *SessionMgr) StartSession(w http.ResponseWriter, r *http.Request) string {
        mgr.mLock.Lock()
        defer mgr.mLock.Unlock()
    
        //无论原来有没有,都重新创建一个新的session
        newSessionID := url.QueryEscape(mgr.NewSessionID())
    
        //存指针
        var session *Session = &Session{mSessionID: newSessionID, mLastTimeAccessed: time.Now(), mValues: make(map[interface{}]interface{})}
        mgr.mSessions[newSessionID] = session
        //让浏览器cookie设置过期时间
        cookie := http.Cookie{Name: mgr.mCookieName, Value: newSessionID, Path: "/", HttpOnly: true, MaxAge: int(mgr.mMaxLifeTime)}
        http.SetCookie(w, &cookie)
    
        return newSessionID
    }
    
    //结束Session
    func (mgr *SessionMgr) EndSession(w http.ResponseWriter, r *http.Request) {
        cookie, err := r.Cookie(mgr.mCookieName)
        if err != nil || cookie.Value == "" {
            return
        } else {
            mgr.mLock.Lock()
            defer mgr.mLock.Unlock()
    
            delete(mgr.mSessions, cookie.Value)
    
            //让浏览器cookie立刻过期
            expiration := time.Now()
            cookie := http.Cookie{Name: mgr.mCookieName, Path: "/", HttpOnly: true, Expires: expiration, MaxAge: -1}
            http.SetCookie(w, &cookie)
        }
    }
    
    //结束session
    func (mgr *SessionMgr) EndSessionBy(sessionID string) {
        mgr.mLock.Lock()
        defer mgr.mLock.Unlock()
    
        delete(mgr.mSessions, sessionID)
    }
    
    //设置session里面的值
    func (mgr *SessionMgr) SetSessionVal(sessionID string, key interface{}, value interface{}) {
        mgr.mLock.Lock()
        defer mgr.mLock.Unlock()
    
        if session, ok := mgr.mSessions[sessionID]; ok {
            session.mValues[key] = value
        }
    }
    
    //得到session里面的值
    func (mgr *SessionMgr) GetSessionVal(sessionID string, key interface{}) (interface{}, bool) {
        mgr.mLock.RLock()
        defer mgr.mLock.RUnlock()
    
        if session, ok := mgr.mSessions[sessionID]; ok {
            if val, ok := session.mValues[key]; ok {
                return val, ok
            }
        }
    
        return nil, false
    }
    
    //得到sessionID列表
    func (mgr *SessionMgr) GetSessionIDList() []string {
        mgr.mLock.RLock()
        defer mgr.mLock.RUnlock()
    
        sessionIDList := make([]string, 0)
    
        for k, _ := range mgr.mSessions {
            sessionIDList = append(sessionIDList, k)
        }
    
        return sessionIDList[0:len(sessionIDList)]
    }
    
    //判断Cookie的合法性(每进入一个页面都需要判断合法性)
    func (mgr *SessionMgr) CheckCookieValid(w http.ResponseWriter, r *http.Request) string {
        var cookie, err = r.Cookie(mgr.mCookieName)
    
        if cookie == nil ||
            err != nil {
            return ""
        }
    
        mgr.mLock.Lock()
        defer mgr.mLock.Unlock()
    
        sessionID := cookie.Value
    
        if session, ok := mgr.mSessions[sessionID]; ok {
            session.mLastTimeAccessed = time.Now() //判断合法性的同时,更新最后的访问时间
            return sessionID
        }
    
        return ""
    }
    
    //更新最后访问时间
    func (mgr *SessionMgr) GetLastAccessTime(sessionID string) time.Time {
        mgr.mLock.RLock()
        defer mgr.mLock.RUnlock()
    
        if session, ok := mgr.mSessions[sessionID]; ok {
            return session.mLastTimeAccessed
        }
    
        return time.Now()
    }
    
    //GC回收
    func (mgr *SessionMgr) GC() {
        mgr.mLock.Lock()
        defer mgr.mLock.Unlock()
    
        for sessionID, session := range mgr.mSessions {
            //删除超过时限的session
            if session.mLastTimeAccessed.Unix()+mgr.mMaxLifeTime < time.Now().Unix() {
                delete(mgr.mSessions, sessionID)
            }
        }
    
        //定时回收
        time.AfterFunc(time.Duration(mgr.mMaxLifeTime)*time.Second, func() { mgr.GC() })
    }
    
    //创建唯一ID
    func (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)
    }
    
    //——————————————————————————
    /*会话*/
    type Session struct {
        mSessionID        string                      //唯一id
        mLastTimeAccessed time.Time                   //最后访问时间
        mValues           map[interface{}]interface{} //其它对应值(保存用户所对应的一些值,比如用户权限之类)
    }

    2.使用方法
    ①定义一个全局变量

    1 var sessionMgr *Helper.SessionMgr = nil //session管理器

     

    ②在程序入口处,创建一个session的对象

    1 //创建session管理器,”TestCookieName”是浏览器中cookie的名字,3600是浏览器cookie的有效时间(秒)  
    2 sessionMgr = Helper.NewSessionMgr("TestCookieName", 3600)

     

    ③在用户登录时进行登录用户合法性判断并设置属性

     1 //处理登录  
     2 func login(w http.ResponseWriter, r *http.Request) {  
     3     if r.Method == "GET" {  
     4         t, _ := template.ParseFiles("web/MgrSvr_login.html")  
     5         t.Execute(w, nil)  
     6   
     7     } else if r.Method == "POST" {  
     8         //请求的是登陆数据,那么执行登陆的逻辑判断  
     9         r.ParseForm()  
    10   
    11         //可以使用template.HTMLEscapeString()来避免用户进行js注入  
    12         username := r.FormValue("username")  
    13         password := r.FormValue("password")  
    14   
    15         //在数据库中得到对应数据  
    16         var userID int = 0  
    17   
    18         userRow := db.QueryRow(loginUserQuery, username, password)  
    19         userRow.Scan(&amp;userID)  
    20   
    21         //TODO:判断用户名和密码  
    22         if userID != 0 {  
    23             //创建客户端对应cookie以及在服务器中进行记录  
    24             var sessionID = sessionMgr.StartSession(w, r)  
    25   
    26             var loginUserInfo = UserInfo{ID: userID, UserName: username, Password: password, Alias: alias,  
    27                 Desc: desc, ChannelAuth: channel_authority, IsSuperAdmin: is_super_admin, IsNewClientAuth: is_newclient_authority,  
    28                 IsPayAuth: is_pay_authority, IsItemsAuth: is_itmes_authority, IsRealtimeAuth: is_realtime_authority,  
    29                 IsPayCodeAuth: is_paycode_authority, IsUserAuth: is_user_authority, IsBgOpAuth: is_bgop_authority, IsHZRaidenNMMWeak: is_hz_raidenn_mmweak,  
    30                 IsManualDataMgr: is_manual_data_mgr, IsManualDataQuery: is_manual_data_query}  
    31   
    32             //踢除重复登录的  
    33             var onlineSessionIDList = sessionMgr.GetSessionIDList()  
    34   
    35             for _, onlineSessionID := range onlineSessionIDList {  
    36                 if userInfo, ok := sessionMgr.GetSessionVal(onlineSessionID, "UserInfo"); ok {  
    37                     if value, ok := userInfo.(UserInfo); ok {  
    38                         if value.ID == userID {  
    39                             sessionMgr.EndSessionBy(onlineSessionID)  
    40                         }  
    41                     }  
    42                 }  
    43             }  
    44   
    45             //设置变量值  
    46             sessionMgr.SetSessionVal(sessionID, "UserInfo", loginUserInfo)  
    47   
    48             //TODO 设置其它数据  
    49   
    50             //TODO 转向成功页面  
    51   
    52             return  
    53         }  
    54     }  
    55 }

     

    ③在用户退出时删除对应session

    1 //处理退出  
    2 func logout(w http.ResponseWriter, r *http.Request) {  
    3     sessionMgr.EndSession(w, r) //用户退出时删除对应session  
    4     http.Redirect(w, r, "/login", http.StatusFound)  
    5     return  
    6 }

     

    ④在每个页面中进行用户合法性验证

    1 func test_session_valid(w http.ResponseWriter, r *http.Request) {  
    2     var sessionID = sessionMgr.CheckCookieValid(w, r)  
    3   
    4     if sessionID == "" {  
    5         http.Redirect(w, r, "/login", http.StatusFound)  
    6         return  
    7     }  
    8 }

     

  • 相关阅读:
    [转]C#读写app.config中的数据
    [转]DirectoryEntry的应用
    js读取xml文档,并实现简单分页
    [转]写给想要做产品经理的同学
    《算法导论》(第二章)算法入门
    《算法导论》中伪代码的约定
    HDU ACM 1284 钱币兑换问题
    《算法导论》(第一部分)(第一章)
    HDU ACM 4554 叛逆的小明
    HDU ACM 1002 A + B Problem II
  • 原文地址:https://www.cnblogs.com/chevin/p/5669940.html
Copyright © 2011-2022 走看看