github.com/qiuhoude/go-web@v0.0.0-20220223060959-ab545e78f20d/prepare/05_session/session/session.go (about) 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 var provides = make(map[string]Provider) 15 16 type ( 17 Provider interface { 18 SessionInit(sid string) (Session, error) 19 SessionRead(sid string) (Session, error) 20 SessionDestroy(sid string) error 21 SessionGC(maxLifeTime int64) 22 } 23 24 Session interface { 25 Set(key, value interface{}) error 26 Get(key interface{}) interface{} 27 Delete(key interface{}) error 28 SessionID() string 29 } 30 ) 31 32 type ( 33 Manager struct { 34 cookieName string 35 lock sync.Mutex 36 maxLifeTime int64 // 最大过期时间 37 provider Provider 38 } 39 ) 40 41 func NewManager(provideName, cookieName string, maxLifeTime int64) (*Manager, error) { 42 provider, ok := provides[provideName] 43 if !ok { 44 return nil, fmt.Errorf("session: unknown provide %q (forgotten import?)", provideName) 45 } 46 return &Manager{ 47 cookieName: cookieName, 48 maxLifeTime: maxLifeTime, 49 provider: provider, 50 }, nil 51 } 52 53 // 生成sessionId 54 func (m *Manager) sessionId() string { 55 b := make([]byte, 32) 56 if _, err := io.ReadFull(rand.Reader, b); err != nil { 57 return "" 58 } 59 return base64.URLEncoding.EncodeToString(b) 60 } 61 62 // 创建session 63 func (m *Manager) SessionStart(rw http.ResponseWriter, req *http.Request) Session { 64 m.lock.Lock() 65 defer m.lock.Unlock() 66 cookie, err := req.Cookie(m.cookieName) 67 if err != nil || cookie.Value == "" { // 获取出错,或者值为nil就重新设置cookie 68 sid := m.sessionId() 69 cookie := http.Cookie{ 70 Name: m.cookieName, 71 Value: url.QueryEscape(sid), 72 Path: "/", 73 //MaxAge: int(m.maxLifeTime), 74 HttpOnly: true, //这个属性是设置是否可通过客户端脚本访问这个设置的cookie 75 } 76 http.SetCookie(rw, &cookie) 77 session, _ := m.provider.SessionInit(sid) 78 return session 79 } else { 80 sid, _ := url.QueryUnescape(cookie.Value) 81 session, _ := m.provider.SessionRead(sid) 82 return session 83 } 84 } 85 86 //重置session 87 func (m *Manager) SessionDestroy(rw http.ResponseWriter, req *http.Request) { 88 cookie, err := req.Cookie(m.cookieName) 89 if err != nil || cookie.Value == "" { 90 return 91 } else { 92 m.lock.Lock() 93 defer m.lock.Unlock() 94 m.provider.SessionDestroy(cookie.Value) 95 expiration := time.Now() 96 cookie := http.Cookie{ 97 Name: m.cookieName, 98 Path: "/", 99 HttpOnly: true, 100 Expires: expiration, 101 } 102 http.SetCookie(rw, &cookie) 103 } 104 } 105 106 func (m *Manager) CookieName() string { 107 return m.cookieName 108 } 109 110 // 过期回收,每间隔 maxLifeTime 时间就来清理一次session 111 func (m *Manager) GC() { 112 m.lock.Lock() 113 defer m.lock.Unlock() 114 m.provider.SessionGC(m.maxLifeTime) 115 time.AfterFunc(time.Duration(m.maxLifeTime)*time.Second, func() { 116 m.GC() 117 }) 118 } 119 120 //注册provide, 不能重复注册,在调用的地方 init中执行 121 func Register(name string, provide Provider) { 122 if provide == nil { 123 panic("session: Register provide is nil") 124 } 125 if _, dup := provides[name]; dup { 126 panic("session: Register called twice for provide " + name) 127 } 128 provides[name] = provide 129 }