对于一些需要对用户进行管理(比如验证操作的权限等)的站点来说,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 }
原文:http://www.cnblogs.com/chevin/p/5669940.html