├── .gitignore ├── README.md ├── providers └── memory │ └── memory.go └── session.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Build and Release Folders 2 | bin-debug/ 3 | bin-release/ 4 | 5 | # Project property files 6 | .actionScriptProperties 7 | .flexProperties 8 | .settings/ 9 | .project -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | this repo will not maintain 2 | 3 | move to [beego/session](https://github.com/astaxie/beego/tree/master/session) -------------------------------------------------------------------------------- /providers/memory/memory.go: -------------------------------------------------------------------------------- 1 | package memory 2 | 3 | import ( 4 | "container/list" 5 | "github.com/astaxie/session" 6 | "sync" 7 | "time" 8 | ) 9 | 10 | var pder = &Provider{list: list.New()} 11 | 12 | type SessionStore struct { 13 | sid string //session id唯一标示 14 | timeAccessed time.Time //最后访问时间 15 | value map[interface{}]interface{} //session里面存储的值 16 | } 17 | 18 | func (st *SessionStore) Set(key, value interface{}) error { 19 | st.value[key] = value 20 | pder.SessionUpdate(st.sid) 21 | return nil 22 | } 23 | 24 | func (st *SessionStore) Get(key interface{}) interface{} { 25 | pder.SessionUpdate(st.sid) 26 | if v, ok := st.value[key]; ok { 27 | return v 28 | } else { 29 | return nil 30 | } 31 | return nil 32 | } 33 | 34 | func (st *SessionStore) Delete(key interface{}) error { 35 | delete(st.value, key) 36 | pder.SessionUpdate(st.sid) 37 | return nil 38 | } 39 | 40 | func (st *SessionStore) SessionID() string { 41 | return st.sid 42 | } 43 | 44 | type Provider struct { 45 | lock sync.Mutex //用来锁 46 | sessions map[string]*list.Element //用来存储在内存 47 | list *list.List //用来做gc 48 | } 49 | 50 | func (pder *Provider) SessionInit(sid string) (session.Session, error) { 51 | pder.lock.Lock() 52 | defer pder.lock.Unlock() 53 | v := make(map[interface{}]interface{}, 0) 54 | newsess := &SessionStore{sid: sid, timeAccessed: time.Now(), value: v} 55 | element := pder.list.PushBack(newsess) 56 | pder.sessions[sid] = element 57 | return newsess, nil 58 | } 59 | 60 | func (pder *Provider) SessionRead(sid string) (session.Session, error) { 61 | if element, ok := pder.sessions[sid]; ok { 62 | return element.Value.(*SessionStore), nil 63 | } else { 64 | sess, err := pder.SessionInit(sid) 65 | return sess, err 66 | } 67 | return nil, nil 68 | } 69 | 70 | func (pder *Provider) SessionDestroy(sid string) error { 71 | if element, ok := pder.sessions[sid]; ok { 72 | delete(pder.sessions, sid) 73 | pder.list.Remove(element) 74 | return nil 75 | } 76 | return nil 77 | } 78 | 79 | func (pder *Provider) SessionGC(maxlifetime int64) { 80 | pder.lock.Lock() 81 | defer pder.lock.Unlock() 82 | 83 | for { 84 | element := pder.list.Back() 85 | if element == nil { 86 | break 87 | } 88 | if (element.Value.(*SessionStore).timeAccessed.Unix() + maxlifetime) < time.Now().Unix() { 89 | pder.list.Remove(element) 90 | delete(pder.sessions, element.Value.(*SessionStore).sid) 91 | } else { 92 | break 93 | } 94 | } 95 | } 96 | 97 | func (pder *Provider) SessionUpdate(sid string) error { 98 | pder.lock.Lock() 99 | defer pder.lock.Unlock() 100 | if element, ok := pder.sessions[sid]; ok { 101 | element.Value.(*SessionStore).timeAccessed = time.Now() 102 | pder.list.MoveToFront(element) 103 | return nil 104 | } 105 | return nil 106 | } 107 | 108 | func init() { 109 | pder.sessions = make(map[string]*list.Element, 0) 110 | session.Register("memory", pder) 111 | } 112 | -------------------------------------------------------------------------------- /session.go: -------------------------------------------------------------------------------- 1 | package session 2 | 3 | import ( 4 | "crypto/rand" 5 | "encoding/base64" 6 | "fmt" 7 | "io" 8 | "net/http" 9 | "net/url" 10 | "sync" 11 | "time" 12 | ) 13 | 14 | type Session interface { 15 | Set(key, value interface{}) error //set session value 16 | Get(key interface{}) interface{} //get session value 17 | Delete(key interface{}) error //delete session value 18 | SessionID() string //back current sessionID 19 | } 20 | 21 | type Provider interface { 22 | SessionInit(sid string) (Session, error) 23 | SessionRead(sid string) (Session, error) 24 | SessionDestroy(sid string) error 25 | SessionGC(maxlifetime int64) 26 | } 27 | 28 | var provides = make(map[string]Provider) 29 | 30 | // Register makes a session provide available by the provided name. 31 | // If Register is called twice with the same name or if driver is nil, 32 | // it panics. 33 | func Register(name string, provide Provider) { 34 | if provide == nil { 35 | panic("session: Register provide is nil") 36 | } 37 | if _, dup := provides[name]; dup { 38 | panic("session: Register called twice for provide " + name) 39 | } 40 | provides[name] = provide 41 | } 42 | 43 | type Manager struct { 44 | cookieName string //private cookiename 45 | lock sync.Mutex // protects session 46 | provider Provider 47 | maxlifetime int64 48 | } 49 | 50 | func NewManager(provideName, cookieName string, maxlifetime int64) (*Manager, error) { 51 | provider, ok := provides[provideName] 52 | if !ok { 53 | return nil, fmt.Errorf("session: unknown provide %q (forgotten import?)", provideName) 54 | } 55 | return &Manager{provider: provider, cookieName: cookieName, maxlifetime: maxlifetime}, nil 56 | } 57 | 58 | //get Session 59 | func (manager *Manager) SessionStart(w http.ResponseWriter, r *http.Request) (session Session) { 60 | manager.lock.Lock() 61 | defer manager.lock.Unlock() 62 | cookie, err := r.Cookie(manager.cookieName) 63 | if err != nil || cookie.Value == "" { 64 | sid := manager.sessionId() 65 | session, _ = manager.provider.SessionInit(sid) 66 | cookie := http.Cookie{Name: manager.cookieName, Value: url.QueryEscape(sid), Path: "/", HttpOnly: true, MaxAge: int(manager.maxlifetime)} 67 | http.SetCookie(w, &cookie) 68 | } else { 69 | sid, _ := url.QueryUnescape(cookie.Value) 70 | session, _ = manager.provider.SessionRead(sid) 71 | } 72 | return 73 | } 74 | 75 | //Destroy sessionid 76 | func (manager *Manager) SessionDestroy(w http.ResponseWriter, r *http.Request) { 77 | cookie, err := r.Cookie(manager.cookieName) 78 | if err != nil || cookie.Value == "" { 79 | return 80 | } else { 81 | manager.lock.Lock() 82 | defer manager.lock.Unlock() 83 | manager.provider.SessionDestroy(cookie.Value) 84 | expiration := time.Now() 85 | cookie := http.Cookie{Name: manager.cookieName, Path: "/", HttpOnly: true, Expires: expiration, MaxAge: -1} 86 | http.SetCookie(w, &cookie) 87 | } 88 | } 89 | 90 | func (manager *Manager) GC() { 91 | manager.lock.Lock() 92 | defer manager.lock.Unlock() 93 | manager.provider.SessionGC(manager.maxlifetime) 94 | time.AfterFunc(time.Duration(manager.maxlifetime)*time.Second, func() { manager.GC() }) 95 | } 96 | 97 | func (manager *Manager) sessionId() string { 98 | b := make([]byte, 32) 99 | if _, err := io.ReadFull(rand.Reader, b); err != nil { 100 | return "" 101 | } 102 | return base64.URLEncoding.EncodeToString(b) 103 | } 104 | --------------------------------------------------------------------------------