Golang的session管理器

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

1.代码如下:

  1 package Helper
  2
  3 import (
  4     “crypto/rand”
  5     “encoding/base64″
  6     “io”
  7     “net/http”
  8     “net/url”
  9     “strconv”
 10     “sync”
 11     “time”
 12 )
 13
 14 /*Session会话管理*/
 15 type SessionMgr struct {
 16     mCookieName  string       //客户端cookie名称
 17     mLock        sync.RWMutex //互斥(保证线程安全)
 18     mMaxLifeTime int64        //垃圾回收时间
 19
 20     mSessions map[string]*Session //保存session的指针[sessionID] = session
 21 }
 22
 23 //创建会话管理器(cookieName:在浏览器中cookie的名字;maxLifeTime:最长生命周期)
 24 func NewSessionMgr(cookieName string, maxLifeTime int64) *SessionMgr {
 25     mgr := &SessionMgr{mCookieName: cookieName, mMaxLifeTime: maxLifeTime, mSessions: make(map[string]*Session)}
 26
 27     //启动定时回收
 28     go mgr.GC()
 29
 30     return mgr
 31 }
 32
 33 //在开始页面登陆页面,开始Session
 34 func (mgr *SessionMgr) StartSession(w http.ResponseWriter, r *http.Request) string {
 35     mgr.mLock.Lock()
 36     defer mgr.mLock.Unlock()
 37
 38     //无论原来有没有,都重新创建一个新的session
 39     newSessionID := url.QueryEscape(mgr.NewSessionID())
 40
 41     //存指针
 42     var session *Session = &Session{mSessionID: newSessionID, mLastTimeAccessed: time.Now(), mValues: make(map[interface{}]interface{})}
 43     mgr.mSessions[newSessionID] = session
 44     //让浏览器cookie设置过期时间
 45     cookie := http.Cookie{Name: mgr.mCookieName, Value: newSessionID, Path: “/”, HttpOnly: true, MaxAge: int(mgr.mMaxLifeTime)}
 46     http.SetCookie(w, &cookie)
 47
 48     return newSessionID
 49 }
 50
 51 //结束Session
 52 func (mgr *SessionMgr) EndSession(w http.ResponseWriter, r *http.Request) {
 53     cookie, err := r.Cookie(mgr.mCookieName)
 54     if err != nil || cookie.Value == “” {
 55         return
 56     } else {
 57         mgr.mLock.Lock()
 58         defer mgr.mLock.Unlock()
 59
 60         delete(mgr.mSessions, cookie.Value)
 61
 62         //让浏览器cookie立刻过期
 63         expiration := time.Now()
 64         cookie := http.Cookie{Name: mgr.mCookieName, Path: “/”, HttpOnly: true, Expires: expiration, MaxAge: -1}
 65         http.SetCookie(w, &cookie)
 66     }
 67 }
 68
 69 //结束session
 70 func (mgr *SessionMgr) EndSessionBy(sessionID string) {
 71     mgr.mLock.Lock()
 72     defer mgr.mLock.Unlock()
 73
 74     delete(mgr.mSessions, sessionID)
 75 }
 76
 77 //设置session里面的值
 78 func (mgr *SessionMgr) SetSessionVal(sessionID string, key interface{}, value interface{}) {
 79     mgr.mLock.Lock()
 80     defer mgr.mLock.Unlock()
 81
 82     if session, ok := mgr.mSessions[sessionID]; ok {
 83         session.mValues[key] = value
 84     }
 85 }
 86
 87 //得到session里面的值
 88 func (mgr *SessionMgr) GetSessionVal(sessionID string, key interface{}) (interface{}, bool) {
 89     mgr.mLock.RLock()
 90     defer mgr.mLock.RUnlock()
 91
 92     if session, ok := mgr.mSessions[sessionID]; ok {
 93         if val, ok := session.mValues[key]; ok {
 94             return val, ok
 95         }
 96     }
 97
 98     return nil, false
 99 }
100
101 //得到sessionID列表
102 func (mgr *SessionMgr) GetSessionIDList() []string {
103     mgr.mLock.RLock()
104     defer mgr.mLock.RUnlock()
105
106     sessionIDList := make([]string, 0)
107
108     for k, _ := range mgr.mSessions {
109         sessionIDList = append(sessionIDList, k)
110     }
111
112     return sessionIDList[0:len(sessionIDList)]
113 }
114
115 //判断Cookie的合法性(每进入一个页面都需要判断合法性)
116 func (mgr *SessionMgr) CheckCookieValid(w http.ResponseWriter, r *http.Request) string {
117     var cookie, err = r.Cookie(mgr.mCookieName)
118
119     if cookie == nil ||
120         err != nil {
121         return “”
122     }
123
124     mgr.mLock.Lock()
125     defer mgr.mLock.Unlock()
126
127     sessionID := cookie.Value
128
129     if session, ok := mgr.mSessions[sessionID]; ok {
130         session.mLastTimeAccessed = time.Now() //判断合法性的同时,更新最后的访问时间
131         return sessionID
132     }
133
134     return “”
135 }
136
137 //更新最后访问时间
138 func (mgr *SessionMgr) GetLastAccessTime(sessionID string) time.Time {
139     mgr.mLock.RLock()
140     defer mgr.mLock.RUnlock()
141
142     if session, ok := mgr.mSessions[sessionID]; ok {
143         return session.mLastTimeAccessed
144     }
145
146     return time.Now()
147 }
148
149 //GC回收
150 func (mgr *SessionMgr) GC() {
151     mgr.mLock.Lock()
152     defer mgr.mLock.Unlock()
153
154     for sessionID, session := range mgr.mSessions {
155         //删除超过时限的session
156         if session.mLastTimeAccessed.Unix()+mgr.mMaxLifeTime < time.Now().Unix() {
157             delete(mgr.mSessions, sessionID)
158         }
159     }
160
161     //定时回收
162     time.AfterFunc(time.Duration(mgr.mMaxLifeTime)*time.Second, func() { mgr.GC() })
163 }
164
165 //创建唯一ID
166 func (mgr *SessionMgr) NewSessionID() string {
167     b := make([]byte, 32)
168     if _, err := io.ReadFull(rand.Reader, b); err != nil {
169         nano := time.Now().UnixNano() //微秒
170         return strconv.FormatInt(nano, 10)
171     }
172     return base64.URLEncoding.EncodeToString(b)
173 }
174
175 //——————————————————————————
176 /*会话*/
177 type Session struct {
178     mSessionID        string                      //唯一id
179     mLastTimeAccessed time.Time                   //最后访问时间
180     mValues           map[interface{}]interface{} //其它对应值(保存用户所对应的一些值,比如用户权限之类)
181 }

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(&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 }
时间: 2024-10-29 19:42:17

Golang的session管理器的相关文章

转:通过Spring Session实现新一代的Session管理

长期以来,session管理就是企业级Java中的一部分,以致于我们潜意识就认为它是已经解决的问题,在最近的记忆中,我们没有看到这个领域有很大的革新. 但是,现代的趋势是微服务以及可水平扩展的原生云应用(cloud native application),它们会挑战过去20多年来我们设计和构建session管理器时的前提假设,并且暴露了现代化session管理器的不足. 本文将会阐述最近发布的Spring Session API如何帮助我们克服眼下session管理方式中的一些不足,在企业级Ja

008-shiro与spring web项目整合【二】认证、授权、session管理

一.认证 1.添加凭证匹配器 添加凭证匹配器实现md5加密校验. 修改applicationContext-shiro.xml: <!-- realm --> <bean id="customRealm" class="com.lhx.ssm.shiro.CustomRealm"> <!-- 将凭证匹配器设置到realm中,realm按照凭证匹配器的要求进行散列 --> <property name="creden

Tomcat源码分析——Session管理分析(上)

前言 对于广大java开发者而已,对于J2EE规范中的Session应该并不陌生,我们可以使用Session管理用户的会话信息,最常见的就是拿Session用来存放用户登录.身份.权限及状态等信息.对于使用Tomcat作为Web容器的大部分开发人员而言,Tomcat是如何实现Session标记用户和管理Session信息的呢? 概要 Session Tomcat内部定义了Session和HttpSession这两个会话相关的接口,其类继承体系如图1所示. 图1 Session类继承体系 图1中额

[转] Spring的session管理

Session管理是企业级Java中的一部分.随着现在的趋势朝着微服务以及可水平扩展的原生云应用发展,传统的session管理逐渐暴露出自己的不足. 本文阐述spring session API如何革新过去的session管理的不足.先阐述一下当前session管理中的问题,然后深入介绍Spring session如何解决这些问题的.最后,将会详细展示Spring session如何运行的,及在项目中怎样使用它. Spring session带来的新功能如下,使得如下功能更加容易实现: 1. 编

Tomcat7.0源码分析——Session管理分析(上)

前言 对于广大java开发者而已,对于J2EE规范中的Session应该并不陌生,我们可以使用Session管理用户的会话信息,最常见的就是拿Session用来存放用户登录.身份.权限及状态等信息.对于使用Tomcat作为Web容器的大部分开发人员而言,Tomcat是如何实现Session标记用户和管理Session信息的呢? 概述 Session Tomcat内部定义了Session和HttpSession这两个会话相关的接口,其类继承体系如图1所示. 图1 Session类继承体系图1中额外

tomcat(9)Session管理

[0]README 0.0)本文部分描述转自"深入剖析tomcat",旨在学习"tomcat-Session管理" 的基础知识: 0.1)Catalina通过一个称为Session 管理器的组件来管理建立的Session对象,该组件由org.apache.catalina.Manager接口来表示.(干货--catalina通过Session管理器组件来管理Session对象) 0.2)Session管理器:需要与一个Context容器相关联,且必须与一个Conte

how tomcat works 读书笔记九 Session管理

在看本文之前,请先查阅相关Session与Cookie的资料. Catalina通过一个叫管理器的组件来完成 session 管理工作,该组件由org.apache.catalina.Manager interface 接口表示.一个管理器通常跟一个上下文容器相关联,它负责创建.更行以及销毁 session 对象并能给任何请求组件返回一个合法的 session. Session对象 uml图如下: 看上图,我们知道我们使用的session其实是javax.servlet.http.HttpSes

通过Spring Session实现新一代的Session管理

长期以来,session管理就是企业级Java中的一部分,以致于我们潜意识就认为它是已经解决的问题,在最近的记忆中,我们没有看到这个领域有很大的革新. 但是,现代的趋势是微服务以及可水平扩展的原生云应用(cloud native application),它们会挑战过去20多年来我们设计和构建session管理器时的前提假设,并且暴露了现代化session管理器的不足. 本文将会阐述最近发布的Spring Session API如何帮助我们克服眼下session管理方式中的一些不足,在企业级Ja

Shiro企业级实战详解,统一的Session管理。

基础的什么配置这些都不说了,百度一下什么都有,直接上干货. Shiro切入点是从web.xml文件,通过filter进行拦截. 直接看DelegatingFilterProxy这个类,很简单,父类就是一个filter,肯定会初始化filter,后面会调用这个方法: @Override protected void initFilterBean() throws ServletException { synchronized (this.delegateMonitor) { if (this.de