Golang的session管理器
本文内容纲要:
对于一些需要对用户进行管理(比如验证操作的权限等)的站点来说,session管理器是必不可少的。下面实现了一个线程安全的简单session管理类。
生产环境:golang1.4.2+win7x64
golang1.4.2+centos6.5×64
1.代码如下:
packageHelper
import(
"crypto/rand"
"encoding/base64"
"io"
"net/http"
"net/url"
"strconv"
"sync"
"time"
)
/*Session会话管理*/
typeSessionMgrstruct{
mCookieNamestring//客户端cookie名称
mLocksync.RWMutex//互斥(保证线程安全)
mMaxLifeTimeint64//垃圾回收时间
mSessionsmap[string]*Session//保存session的指针[sessionID]=session
}
//创建会话管理器(cookieName:在浏览器中cookie的名字;maxLifeTime:最长生命周期)
funcNewSessionMgr(cookieNamestring,maxLifeTimeint64)*SessionMgr{
mgr:=&SessionMgr{mCookieName:cookieName,mMaxLifeTime:maxLifeTime,mSessions:make(map[string]*Session)}
//启动定时回收
gomgr.GC()
returnmgr
}
//在开始页面登陆页面,开始Session
func(mgr*SessionMgr)StartSession(whttp.ResponseWriter,r*http.Request)string{
mgr.mLock.Lock()
defermgr.mLock.Unlock()
//无论原来有没有,都重新创建一个新的session
newSessionID:=url.QueryEscape(mgr.NewSessionID())
//存指针
varsession*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)
returnnewSessionID
}
//结束Session
func(mgr*SessionMgr)EndSession(whttp.ResponseWriter,r*http.Request){
cookie,err:=r.Cookie(mgr.mCookieName)
iferr!=nil||cookie.Value==""{
return
}else{
mgr.mLock.Lock()
defermgr.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(sessionIDstring){
mgr.mLock.Lock()
defermgr.mLock.Unlock()
delete(mgr.mSessions,sessionID)
}
//设置session里面的值
func(mgr*SessionMgr)SetSessionVal(sessionIDstring,keyinterface{},valueinterface{}){
mgr.mLock.Lock()
defermgr.mLock.Unlock()
ifsession,ok:=mgr.mSessions[sessionID];ok{
session.mValues[key]=value
}
}
//得到session里面的值
func(mgr*SessionMgr)GetSessionVal(sessionIDstring,keyinterface{})(interface{},bool){
mgr.mLock.RLock()
defermgr.mLock.RUnlock()
ifsession,ok:=mgr.mSessions[sessionID];ok{
ifval,ok:=session.mValues[key];ok{
returnval,ok
}
}
returnnil,false
}
//得到sessionID列表
func(mgr*SessionMgr)GetSessionIDList()[]string{
mgr.mLock.RLock()
defermgr.mLock.RUnlock()
sessionIDList:=make([]string,0)
fork,_:=rangemgr.mSessions{
sessionIDList=append(sessionIDList,k)
}
returnsessionIDList[0:len(sessionIDList)]
}
//判断Cookie的合法性(每进入一个页面都需要判断合法性)
func(mgr*SessionMgr)CheckCookieValid(whttp.ResponseWriter,r*http.Request)string{
varcookie,err=r.Cookie(mgr.mCookieName)
ifcookie==nil||
err!=nil{
return""
}
mgr.mLock.Lock()
defermgr.mLock.Unlock()
sessionID:=cookie.Value
ifsession,ok:=mgr.mSessions[sessionID];ok{
session.mLastTimeAccessed=time.Now()//判断合法性的同时,更新最后的访问时间
returnsessionID
}
return""
}
//更新最后访问时间
func(mgr*SessionMgr)GetLastAccessTime(sessionIDstring)time.Time{
mgr.mLock.RLock()
defermgr.mLock.RUnlock()
ifsession,ok:=mgr.mSessions[sessionID];ok{
returnsession.mLastTimeAccessed
}
returntime.Now()
}
//GC回收
func(mgr*SessionMgr)GC(){
mgr.mLock.Lock()
defermgr.mLock.Unlock()
forsessionID,session:=rangemgr.mSessions{
//删除超过时限的session
ifsession.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()//微秒
returnstrconv.FormatInt(nano,10)
}
returnbase64.URLEncoding.EncodeToString(b)
}
//——————————————————————————
/*会话*/
typeSessionstruct{
mSessionIDstring//唯一id
mLastTimeAccessedtime.Time//最后访问时间
mValuesmap[interface{}]interface{}//其它对应值(保存用户所对应的一些值,比如用户权限之类)
}
2.使用方法
①定义一个全局变量
1varsessionMgr*Helper.SessionMgr=nil//session管理器
②在程序入口处,创建一个session的对象
1//创建session管理器,”TestCookieName”是浏览器中cookie的名字,3600是浏览器cookie的有效时间(秒)
2sessionMgr=Helper.NewSessionMgr("TestCookieName",3600)
③在用户登录时进行登录用户合法性判断并设置属性
1//处理登录
2funclogin(whttp.ResponseWriter,r*http.Request){
3ifr.Method=="GET"{
4t,_:=template.ParseFiles("web/MgrSvr_login.html")
5t.Execute(w,nil)
6
7}elseifr.Method=="POST"{
8//请求的是登陆数据,那么执行登陆的逻辑判断
9r.ParseForm()
10
11//可以使用template.HTMLEscapeString()来避免用户进行js注入
12username:=r.FormValue("username")
13password:=r.FormValue("password")
14
15//在数据库中得到对应数据
16varuserIDint=0
17
18userRow:=db.QueryRow(loginUserQuery,username,password)
19userRow.Scan(&userID)
20
21//TODO:判断用户名和密码
22ifuserID!=0{
23//创建客户端对应cookie以及在服务器中进行记录
24varsessionID=sessionMgr.StartSession(w,r)
25
26varloginUserInfo=UserInfo{ID:userID,UserName:username,Password:password,Alias:alias,
27Desc:desc,ChannelAuth:channel_authority,IsSuperAdmin:is_super_admin,IsNewClientAuth:is_newclient_authority,
28IsPayAuth:is_pay_authority,IsItemsAuth:is_itmes_authority,IsRealtimeAuth:is_realtime_authority,
29IsPayCodeAuth:is_paycode_authority,IsUserAuth:is_user_authority,IsBgOpAuth:is_bgop_authority,IsHZRaidenNMMWeak:is_hz_raidenn_mmweak,
30IsManualDataMgr:is_manual_data_mgr,IsManualDataQuery:is_manual_data_query}
31
32//踢除重复登录的
33varonlineSessionIDList=sessionMgr.GetSessionIDList()
34
35for_,onlineSessionID:=rangeonlineSessionIDList{
36ifuserInfo,ok:=sessionMgr.GetSessionVal(onlineSessionID,"UserInfo");ok{
37ifvalue,ok:=userInfo.(UserInfo);ok{
38ifvalue.ID==userID{
39sessionMgr.EndSessionBy(onlineSessionID)
40}
41}
42}
43}
44
45//设置变量值
46sessionMgr.SetSessionVal(sessionID,"UserInfo",loginUserInfo)
47
48//TODO设置其它数据
49
50//TODO转向成功页面
51
52return
53}
54}
55}
③在用户退出时删除对应session
1//处理退出
2funclogout(whttp.ResponseWriter,r*http.Request){
3sessionMgr.EndSession(w,r)//用户退出时删除对应session
4http.Redirect(w,r,"/login",http.StatusFound)
5return
6}
④在每个页面中进行用户合法性验证
1functest_session_valid(whttp.ResponseWriter,r*http.Request){
2varsessionID=sessionMgr.CheckCookieValid(w,r)
3
4ifsessionID==""{
5http.Redirect(w,r,"/login",http.StatusFound)
6return
7}
8}
本文内容总结:
原文链接:https://www.cnblogs.com/chevin/p/5669940.html