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: -}
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, ) for k, _ := range mgr.mSessions {
sessionIDList = append(sessionIDList, k)
} return sessionIDList[: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, )
if _, err := io.ReadFull(rand.Reader, b); err != nil {
nano := time.Now().UnixNano() //微秒
return strconv.FormatInt(nano, )
}
return base64.URLEncoding.EncodeToString(b)
} //——————————————————————————
/*会话*/
type Session struct {
mSessionID string //唯一id
mLastTimeAccessed time.Time //最后访问时间
mValues map[interface{}]interface{} //其它对应值(保存用户所对应的一些值,比如用户权限之类)
}
2.使用方法
①定义一个全局变量
var sessionMgr *Helper.SessionMgr = nil //session管理器
②在程序入口处,创建一个session的对象
//创建session管理器,”TestCookieName”是浏览器中cookie的名字,3600是浏览器cookie的有效时间(秒)
sessionMgr = Helper.NewSessionMgr("TestCookieName", )
③在用户登录时进行登录用户合法性判断并设置属性
//处理登录
func login(w http.ResponseWriter, r *http.Request) {
if r.Method == "GET" {
t, _ := template.ParseFiles("web/MgrSvr_login.html")
t.Execute(w, nil) } else if r.Method == "POST" {
//请求的是登陆数据,那么执行登陆的逻辑判断
r.ParseForm() //可以使用template.HTMLEscapeString()来避免用户进行js注入
username := r.FormValue("username")
password := r.FormValue("password") //在数据库中得到对应数据
var userID int = userRow := db.QueryRow(loginUserQuery, username, password)
userRow.Scan(&userID) //TODO:判断用户名和密码
if userID != {
//创建客户端对应cookie以及在服务器中进行记录
var sessionID = sessionMgr.StartSession(w, r) var loginUserInfo = UserInfo{ID: userID, UserName: username, Password: password, Alias: alias,
Desc: desc, ChannelAuth: channel_authority, IsSuperAdmin: is_super_admin, IsNewClientAuth: is_newclient_authority,
IsPayAuth: is_pay_authority, IsItemsAuth: is_itmes_authority, IsRealtimeAuth: is_realtime_authority,
IsPayCodeAuth: is_paycode_authority, IsUserAuth: is_user_authority, IsBgOpAuth: is_bgop_authority, IsHZRaidenNMMWeak: is_hz_raidenn_mmweak,
IsManualDataMgr: is_manual_data_mgr, IsManualDataQuery: is_manual_data_query} //踢除重复登录的
var onlineSessionIDList = sessionMgr.GetSessionIDList() for _, onlineSessionID := range onlineSessionIDList {
if userInfo, ok := sessionMgr.GetSessionVal(onlineSessionID, "UserInfo"); ok {
if value, ok := userInfo.(UserInfo); ok {
if value.ID == userID {
sessionMgr.EndSessionBy(onlineSessionID)
}
}
}
} //设置变量值
sessionMgr.SetSessionVal(sessionID, "UserInfo", loginUserInfo) //TODO 设置其它数据 //TODO 转向成功页面 return
}
}
}
③在用户退出时删除对应session
//处理退出
func logout(w http.ResponseWriter, r *http.Request) {
sessionMgr.EndSession(w, r) //用户退出时删除对应session
http.Redirect(w, r, "/login", http.StatusFound)
return
}
④在每个页面中进行用户合法性验证
func test_session_valid(w http.ResponseWriter, r *http.Request) {
var sessionID = sessionMgr.CheckCookieValid(w, r)
if sessionID == "" {
http.Redirect(w, r, "/login", http.StatusFound)
return
}
}
Golang的session管理器的更多相关文章
- tomcat源码阅读之session管理器(Manager)
一.UML图分析: (一) Session: Session保存了一个客户端访问服务器时,服务器专门为这个客户端建立一个session用来保存相关的会话信息,session有一个有效时间,这个时间默认 ...
- how tomcat works 读书笔记九 Session管理
在看本文之前,请先查阅相关Session与Cookie的资料. 这篇资料不错 http://blog.csdn.net/fangaoxin/article/details/6952954 Catali ...
- golang的包管理---vendor/dep等
首先关于vendor 1 提出问题 我们知道,一个工程稍大一点,通常会依赖各种各样的包.而Go使用统一的GOPATH管理依赖包,且每个包仅保留一个版本.而不同的依赖包由各自的版本工具独立管理,所以当所 ...
- Shiro在Spring session管理
会话管理 在shiro里面可以发现所有的用户的会话信息都会由Shiro来进行控制,那么也就是说只要是与用户有关的一切的处理信息操作都可以通过Shiro取得,实际上可以取得的信息可以有用户名.主机名称等 ...
- 通过Spring Session实现新一代的Session管理
长期以来,session管理就是企业级Java中的一部分,以致于我们潜意识就认为它是已经解决的问题,在最近的记忆中,我们没有看到这个领域有很大的革新. 但是,现代的趋势是微服务以及可水平扩展的原生云应 ...
- TOMCAT8源码分析——SESSION管理分析(上)
前言 对于广大java开发者而已,对于J2EE规范中的Session应该并不陌生,我们可以使用Session管理用户的会话信息,最常见的就是拿Session用来存放用户登录.身份.权限及状态等信息.对 ...
- Tomcat源码分析——Session管理分析(下)
前言 在<TOMCAT源码分析——SESSION管理分析(上)>一文中我介绍了Session.Session管理器,还以StandardManager为例介绍了Session管理器的初始化 ...
- Tomcat源码分析——Session管理分析(上)
前言 对于广大java开发者而已,对于J2EE规范中的Session应该并不陌生,我们可以使用Session管理用户的会话信息,最常见的就是拿Session用来存放用户登录.身份.权限及状态等信息.对 ...
- 008-shiro与spring web项目整合【二】认证、授权、session管理
一.认证 1.添加凭证匹配器 添加凭证匹配器实现md5加密校验. 修改applicationContext-shiro.xml: <!-- realm --> <bean id=&q ...
随机推荐
- 缩点:Power Plant;
题目传送门:[UVALive 6437]Power Plant 题目大意:T组数据,给定一幅带权图(n, m), 然后给定k个点, 与图中存在有若干条边.每个点都要至少要和这k个点的一个点直接或间接相 ...
- opencv学习之路(17)、边缘检测
一.概述 二.canny边缘检测 #include "opencv2/opencv.hpp" using namespace cv; void main() { //Canny边缘 ...
- JAVA基础部分 JDK和JRE以及JVM
第一部分: 一.dos命令 *快捷查看电脑ip: Win + R进入cmd;输入ipconfig/all查看IPv4:192.168.0.xxx(首选); 基本命令: cd进入目录:d: 直接进入盘符 ...
- 线性回归、Logistic回归、Softmax回归
线性回归(Linear Regression) 什么是回归? 给定一些数据,{(x1,y1),(x2,y2)…(xn,yn) },x的值来预测y的值,通常地,y的值是连续的就是回归问题,y的值是离散的 ...
- bzoj 3670 动物园 - kmp - 动态规划
Description 近日,园长发现动物园中好吃懒做的动物越来越多了.例如企鹅,只会卖萌向游客要吃的.为了整治动物园的不良风气,让动物们凭自己的真才实学向游客要吃的,园长决定开设算法班,让动物们学习 ...
- bzoj 2820 YY的GCD - 莫比乌斯反演 - 线性筛
Description 神犇YY虐完数论后给傻×kAc出了一题给定N, M,求1<=x<=N, 1<=y<=M且gcd(x, y)为质数的(x, y)有多少对kAc这种 傻×必 ...
- Windows 动态链接库DLL使用
转载:https://blog.csdn.net/heyabo/article/details/8721611 转载:https://www.cnblogs.com/jin521/p/5598529. ...
- python --- 14 递归 二分法查找
一.递归 1.函数自己调用自己 2.官方说明最大深度1000,但跑不到1000,要看解释器, 实测998 3.使⽤递归来遍历各种树形结构 二. 二分法查找 掐头结尾取中间 , 必须是有序序列 ...
- Python3基础 list [] 创建空列表
Python : 3.7.0 OS : Ubuntu 18.04.1 LTS IDE : PyCharm 2018.2.4 Conda ...
- linux内核中的最简单的输入输出调度算法noop
1. noop是什么? noop是一种输入输出调度算法 2. noop的别称 又称为电梯调度算法 3. noop原理是怎样的? 将输入输出请求放到一个FIFO队列中,然后按次序执行队列中的输入输出请求 ...