25736968 by astaxie

session

1. session move from astaxie/session to beego/session
2. support 4 type session
1 parent 69f40ad1
...@@ -32,7 +32,7 @@ func (this *MainController) Get() { ...@@ -32,7 +32,7 @@ func (this *MainController) Get() {
32 } 32 }
33 33
34 func main() { 34 func main() {
35 beego.RegisterController("/", &MainController{}) 35 beego.Router("/", &MainController{})
36 //beego.HttpPort = 8080 // default 36 //beego.HttpPort = 8080 // default
37 beego.Run() 37 beego.Run()
38 } 38 }
...@@ -54,16 +54,16 @@ Some associated tools for beego reside in:[bee](https://github.com/astaxie/bee) ...@@ -54,16 +54,16 @@ Some associated tools for beego reside in:[bee](https://github.com/astaxie/bee)
54 ============ 54 ============
55 In beego, a route is a struct paired with a URL-matching pattern. The struct has many method with the same name of http method to serve the http response. Each route is associated with a block. 55 In beego, a route is a struct paired with a URL-matching pattern. The struct has many method with the same name of http method to serve the http response. Each route is associated with a block.
56 ```go 56 ```go
57 beego.RegisterController("/", &controllers.MainController{}) 57 beego.Router("/", &controllers.MainController{})
58 beego.RegisterController("/admin", &admin.UserController{}) 58 beego.Router("/admin", &admin.UserController{})
59 beego.RegisterController("/admin/index", &admin.ArticleController{}) 59 beego.Router("/admin/index", &admin.ArticleController{})
60 beego.RegisterController("/admin/addpkg", &admin.AddController{}) 60 beego.Router("/admin/addpkg", &admin.AddController{})
61 ``` 61 ```
62 You can specify custom regular expressions for routes: 62 You can specify custom regular expressions for routes:
63 ```go 63 ```go
64 beego.RegisterController("/admin/editpkg/:id([0-9]+)", &admin.EditController{}) 64 beego.Router("/admin/editpkg/:id([0-9]+)", &admin.EditController{})
65 beego.RegisterController("/admin/delpkg/:id([0-9]+)", &admin.DelController{}) 65 beego.Router("/admin/delpkg/:id([0-9]+)", &admin.DelController{})
66 beego.RegisterController("/:pkg(.*)", &controllers.MainController{}) 66 beego.Router("/:pkg(.*)", &controllers.MainController{})
67 ``` 67 ```
68 You can also create routes for static files: 68 You can also create routes for static files:
69 69
...@@ -87,7 +87,7 @@ beego.Filter(FilterUser) ...@@ -87,7 +87,7 @@ beego.Filter(FilterUser)
87 ``` 87 ```
88 You can also apply filters only when certain REST URL Parameters exist: 88 You can also apply filters only when certain REST URL Parameters exist:
89 ```go 89 ```go
90 beego.RegisterController("/:id([0-9]+)", &admin.EditController{}) 90 beego.Router("/:id([0-9]+)", &admin.EditController{})
91 beego.FilterParam("id", func(rw http.ResponseWriter, r *http.Request) { 91 beego.FilterParam("id", func(rw http.ResponseWriter, r *http.Request) {
92 ... 92 ...
93 }) 93 })
......
...@@ -2,8 +2,7 @@ package beego ...@@ -2,8 +2,7 @@ package beego
2 2
3 import ( 3 import (
4 "fmt" 4 "fmt"
5 "github.com/astaxie/session" 5 "github.com/astaxie/beego/session"
6 _ "github.com/astaxie/session/providers/memory"
7 "html/template" 6 "html/template"
8 "net" 7 "net"
9 "net/http" 8 "net/http"
...@@ -31,9 +30,10 @@ var ( ...@@ -31,9 +30,10 @@ var (
31 AppConfig *Config 30 AppConfig *Config
32 //related to session 31 //related to session
33 SessionOn bool // wheather auto start session,default is false 32 SessionOn bool // wheather auto start session,default is false
34 SessionProvider string // default session provider memory 33 SessionProvider string // default session provider memory mysql redis
35 SessionName string // sessionName cookie's name 34 SessionName string // sessionName cookie's name
36 SessionGCMaxLifetime int64 // session's gc maxlifetime 35 SessionGCMaxLifetime int64 // session's gc maxlifetime
36 SessionSavePath string // session savepath if use mysql/redis/file this set to the connectinfo
37 UseFcgi bool 37 UseFcgi bool
38 38
39 GlobalSessions *session.Manager //GlobalSessions 39 GlobalSessions *session.Manager //GlobalSessions
...@@ -60,6 +60,7 @@ func init() { ...@@ -60,6 +60,7 @@ func init() {
60 SessionProvider = "memory" 60 SessionProvider = "memory"
61 SessionName = "beegosessionID" 61 SessionName = "beegosessionID"
62 SessionGCMaxLifetime = 3600 62 SessionGCMaxLifetime = 3600
63 SessionSavePath = ""
63 UseFcgi = false 64 UseFcgi = false
64 } else { 65 } else {
65 HttpAddr = AppConfig.String("httpaddr") 66 HttpAddr = AppConfig.String("httpaddr")
...@@ -109,6 +110,11 @@ func init() { ...@@ -109,6 +110,11 @@ func init() {
109 } else { 110 } else {
110 SessionName = ar 111 SessionName = ar
111 } 112 }
113 if ar := AppConfig.String("sessionsavepath"); ar == "" {
114 SessionSavePath = ""
115 } else {
116 SessionSavePath = ar
117 }
112 if ar, err := AppConfig.Int("sessiongcmaxlifetime"); err != nil && ar != 0 { 118 if ar, err := AppConfig.Int("sessiongcmaxlifetime"); err != nil && ar != 0 {
113 int64val, _ := strconv.ParseInt(strconv.Itoa(ar), 10, 64) 119 int64val, _ := strconv.ParseInt(strconv.Itoa(ar), 10, 64)
114 SessionGCMaxLifetime = int64val 120 SessionGCMaxLifetime = int64val
...@@ -222,7 +228,7 @@ func Run() { ...@@ -222,7 +228,7 @@ func Run() {
222 BeeApp.Router(`/debug/pprof/:pp([\w]+)`, &ProfController{}) 228 BeeApp.Router(`/debug/pprof/:pp([\w]+)`, &ProfController{})
223 } 229 }
224 if SessionOn { 230 if SessionOn {
225 GlobalSessions, _ = session.NewManager(SessionProvider, SessionName, SessionGCMaxLifetime) 231 GlobalSessions, _ = session.NewManager(SessionProvider, SessionName, SessionGCMaxLifetime, SessionSavePath)
226 go GlobalSessions.GC() 232 go GlobalSessions.GC()
227 } 233 }
228 err := BuildTemplate(ViewsPath) 234 err := BuildTemplate(ViewsPath)
......
...@@ -4,7 +4,7 @@ import ( ...@@ -4,7 +4,7 @@ import (
4 "bytes" 4 "bytes"
5 "encoding/json" 5 "encoding/json"
6 "encoding/xml" 6 "encoding/xml"
7 "github.com/astaxie/session" 7 "github.com/astaxie/beego/session"
8 "html/template" 8 "html/template"
9 "io/ioutil" 9 "io/ioutil"
10 "net/http" 10 "net/http"
...@@ -51,7 +51,6 @@ func (c *Controller) Prepare() { ...@@ -51,7 +51,6 @@ func (c *Controller) Prepare() {
51 } 51 }
52 52
53 func (c *Controller) Finish() { 53 func (c *Controller) Finish() {
54
55 } 54 }
56 55
57 func (c *Controller) Get() { 56 func (c *Controller) Get() {
...@@ -82,21 +81,6 @@ func (c *Controller) Options() { ...@@ -82,21 +81,6 @@ func (c *Controller) Options() {
82 http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", 405) 81 http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", 405)
83 } 82 }
84 83
85 func (c *Controller) SetSession(name string, value interface{}) {
86 ss := c.StartSession()
87 ss.Set(name, value)
88 }
89
90 func (c *Controller) GetSession(name string) interface{} {
91 ss := c.StartSession()
92 return ss.Get(name)
93 }
94
95 func (c *Controller) DelSession(name string) {
96 ss := c.StartSession()
97 ss.Delete(name)
98 }
99
100 func (c *Controller) Render() error { 84 func (c *Controller) Render() error {
101 rb, err := c.RenderBytes() 85 rb, err := c.RenderBytes()
102 86
...@@ -190,7 +174,25 @@ func (c *Controller) Input() url.Values { ...@@ -190,7 +174,25 @@ func (c *Controller) Input() url.Values {
190 return c.Ctx.Request.Form 174 return c.Ctx.Request.Form
191 } 175 }
192 176
193 func (c *Controller) StartSession() (sess session.Session) { 177 func (c *Controller) StartSession() (sess session.SessionStore) {
194 sess = GlobalSessions.SessionStart(c.Ctx.ResponseWriter, c.Ctx.Request) 178 sess = GlobalSessions.SessionStart(c.Ctx.ResponseWriter, c.Ctx.Request)
195 return 179 return
196 } 180 }
181
182 func (c *Controller) SetSession(name string, value interface{}) {
183 ss := c.StartSession()
184 defer ss.SessionRelease()
185 ss.Set(name, value)
186 }
187
188 func (c *Controller) GetSession(name string) interface{} {
189 ss := c.StartSession()
190 defer ss.SessionRelease()
191 return ss.Get(name)
192 }
193
194 func (c *Controller) DelSession(name string) {
195 ss := c.StartSession()
196 defer ss.SessionRelease()
197 ss.Delete(name)
198 }
......
1 package session
2
3 import (
4 "io/ioutil"
5 "os"
6 "path"
7 "path/filepath"
8 "sync"
9 "time"
10 )
11
12 var (
13 filepder = &FileProvider{}
14 gcmaxlifetime int64
15 )
16
17 type FileSessionStore struct {
18 f *os.File
19 sid string
20 lock sync.RWMutex
21 values map[interface{}]interface{}
22 }
23
24 func (fs *FileSessionStore) Set(key, value interface{}) error {
25 fs.lock.Lock()
26 defer fs.lock.Unlock()
27 fs.values[key] = value
28 fs.updatecontent()
29 return nil
30 }
31
32 func (fs *FileSessionStore) Get(key interface{}) interface{} {
33 fs.lock.RLock()
34 defer fs.lock.RUnlock()
35 fs.updatecontent()
36 if v, ok := fs.values[key]; ok {
37 return v
38 } else {
39 return nil
40 }
41 return nil
42 }
43
44 func (fs *FileSessionStore) Delete(key interface{}) error {
45 fs.lock.Lock()
46 defer fs.lock.Unlock()
47 delete(fs.values, key)
48 fs.updatecontent()
49 return nil
50 }
51
52 func (fs *FileSessionStore) SessionID() string {
53 return fs.sid
54 }
55
56 func (fs *FileSessionStore) SessionRelease() {
57 fs.f.Close()
58 }
59
60 func (fs *FileSessionStore) updatecontent() {
61 b, err := encodeGob(fs.values)
62 if err != nil {
63 return
64 }
65 fs.f.Write(b)
66 }
67
68 type FileProvider struct {
69 maxlifetime int64
70 savePath string
71 }
72
73 func (fp *FileProvider) SessionInit(maxlifetime int64, savePath string) error {
74 fp.maxlifetime = maxlifetime
75 fp.savePath = savePath
76 return nil
77 }
78
79 func (fp *FileProvider) SessionRead(sid string) (SessionStore, error) {
80 err := os.MkdirAll(path.Join(fp.savePath, string(sid[0]), string(sid[1])), 0777)
81 if err != nil {
82 println(err.Error())
83 }
84 _, err = os.Stat(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid))
85 var f *os.File
86 if err == nil {
87 f, err = os.OpenFile(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid), os.O_RDWR, 0777)
88 } else if os.IsNotExist(err) {
89 f, err = os.Create(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid))
90 } else {
91 return nil, err
92 }
93 os.Chtimes(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid), time.Now(), time.Now())
94 var kv map[interface{}]interface{}
95 b, err := ioutil.ReadAll(f)
96 if err != nil {
97 return nil, err
98 }
99 if len(b) == 0 {
100 kv = make(map[interface{}]interface{})
101 } else {
102 kv, err = decodeGob(b)
103 if err != nil {
104 return nil, err
105 }
106 }
107 f.Close()
108 f, err = os.Create(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid))
109 ss := &FileSessionStore{f: f, sid: sid, values: kv}
110 return ss, nil
111 }
112
113 func (fp *FileProvider) SessionDestroy(sid string) error {
114 os.Remove(path.Join(fp.savePath))
115 return nil
116 }
117
118 func (fp *FileProvider) SessionGC() {
119 gcmaxlifetime = fp.maxlifetime
120 filepath.Walk(fp.savePath, gcpath)
121 }
122
123 func gcpath(path string, info os.FileInfo, err error) error {
124 if err != nil {
125 return err
126 }
127 if info.IsDir() {
128 return nil
129 }
130 if (info.ModTime().Unix() + gcmaxlifetime) < time.Now().Unix() {
131 os.Remove(path)
132 }
133 return nil
134 }
135
136 func init() {
137 Register("file", filepder)
138 }
1 package session
2
3 import (
4 "bytes"
5 "encoding/gob"
6 )
7
8 func init() {
9 gob.Register([]interface{}{})
10 gob.Register(map[int]interface{}{})
11 gob.Register(map[string]interface{}{})
12 gob.Register(map[interface{}]interface{}{})
13 gob.Register(map[string]string{})
14 gob.Register(map[int]string{})
15 gob.Register(map[int]int{})
16 gob.Register(map[int]int64{})
17 }
18
19 func encodeGob(obj map[interface{}]interface{}) ([]byte, error) {
20 buf := bytes.NewBuffer(nil)
21 enc := gob.NewEncoder(buf)
22 err := enc.Encode(obj)
23 if err != nil {
24 return []byte(""), err
25 }
26 return buf.Bytes(), nil
27 }
28
29 func decodeGob(encoded []byte) (map[interface{}]interface{}, error) {
30 buf := bytes.NewBuffer(encoded)
31 dec := gob.NewDecoder(buf)
32 var out map[interface{}]interface{}
33 err := dec.Decode(&out)
34 if err != nil {
35 return nil, err
36 }
37 return out, nil
38 }
1 package session
2
3 import (
4 "container/list"
5 "sync"
6 "time"
7 )
8
9 var mempder = &MemProvider{list: list.New(), sessions: make(map[string]*list.Element)}
10
11 type MemSessionStore struct {
12 sid string //session id唯一标示
13 timeAccessed time.Time //最后访问时间
14 value map[interface{}]interface{} //session里面存储的值
15 lock sync.RWMutex
16 }
17
18 func (st *MemSessionStore) Set(key, value interface{}) error {
19 st.lock.Lock()
20 defer st.lock.Unlock()
21 st.value[key] = value
22 return nil
23 }
24
25 func (st *MemSessionStore) Get(key interface{}) interface{} {
26 st.lock.RLock()
27 defer st.lock.RUnlock()
28 if v, ok := st.value[key]; ok {
29 return v
30 } else {
31 return nil
32 }
33 return nil
34 }
35
36 func (st *MemSessionStore) Delete(key interface{}) error {
37 st.lock.Lock()
38 defer st.lock.Unlock()
39 delete(st.value, key)
40 return nil
41 }
42
43 func (st *MemSessionStore) SessionID() string {
44 return st.sid
45 }
46
47 func (st *MemSessionStore) SessionRelease() {
48
49 }
50
51 type MemProvider struct {
52 lock sync.RWMutex //用来锁
53 sessions map[string]*list.Element //用来存储在内存
54 list *list.List //用来做gc
55 maxlifetime int64
56 savePath string
57 }
58
59 func (pder *MemProvider) SessionInit(maxlifetime int64, savePath string) error {
60 pder.maxlifetime = maxlifetime
61 pder.savePath = savePath
62 return nil
63 }
64
65 func (pder *MemProvider) SessionRead(sid string) (SessionStore, error) {
66 pder.lock.RLock()
67 if element, ok := pder.sessions[sid]; ok {
68 go pder.SessionUpdate(sid)
69 pder.lock.RUnlock()
70 return element.Value.(*MemSessionStore), nil
71 } else {
72 pder.lock.RUnlock()
73 pder.lock.Lock()
74 newsess := &MemSessionStore{sid: sid, timeAccessed: time.Now(), value: make(map[interface{}]interface{})}
75 element := pder.list.PushBack(newsess)
76 pder.sessions[sid] = element
77 pder.lock.Unlock()
78 return newsess, nil
79 }
80 return nil, nil
81 }
82
83 func (pder *MemProvider) SessionDestroy(sid string) error {
84 pder.lock.Lock()
85 defer pder.lock.Unlock()
86 if element, ok := pder.sessions[sid]; ok {
87 delete(pder.sessions, sid)
88 pder.list.Remove(element)
89 return nil
90 }
91 return nil
92 }
93
94 func (pder *MemProvider) SessionGC() {
95 pder.lock.RLock()
96 for {
97 element := pder.list.Back()
98 if element == nil {
99 break
100 }
101 if (element.Value.(*MemSessionStore).timeAccessed.Unix() + pder.maxlifetime) < time.Now().Unix() {
102 pder.lock.RUnlock()
103 pder.lock.Lock()
104 pder.list.Remove(element)
105 delete(pder.sessions, element.Value.(*MemSessionStore).sid)
106 pder.lock.Unlock()
107 pder.lock.RLock()
108 } else {
109 break
110 }
111 }
112 pder.lock.RUnlock()
113 }
114
115 func (pder *MemProvider) SessionUpdate(sid string) error {
116 pder.lock.RLock()
117 defer pder.lock.RUnlock()
118 if element, ok := pder.sessions[sid]; ok {
119 element.Value.(*MemSessionStore).timeAccessed = time.Now()
120 pder.list.MoveToFront(element)
121 return nil
122 }
123 return nil
124 }
125
126 func init() {
127 Register("memory", mempder)
128 }
1 package session
2
3 //CREATE TABLE `session` (
4 // `session_key` char(64) NOT NULL,
5 // `session_data` blob,
6 // `session_expiry` int(11) unsigned NOT NULL,
7 // PRIMARY KEY (`session_key`)
8 //) ENGINE=MyISAM DEFAULT CHARSET=utf8;
9
10 import (
11 "database/sql"
12 _ "github.com/go-sql-driver/mysql"
13 "sync"
14 "time"
15 )
16
17 var mysqlpder = &MysqlProvider{}
18
19 type MysqlSessionStore struct {
20 c *sql.DB
21 sid string
22 lock sync.RWMutex
23 values map[interface{}]interface{}
24 }
25
26 func (st *MysqlSessionStore) Set(key, value interface{}) error {
27 st.lock.Lock()
28 defer st.lock.Unlock()
29 st.values[key] = value
30 st.updatemysql()
31 return nil
32 }
33
34 func (st *MysqlSessionStore) Get(key interface{}) interface{} {
35 st.lock.RLock()
36 defer st.lock.RUnlock()
37 if v, ok := st.values[key]; ok {
38 return v
39 } else {
40 return nil
41 }
42 return nil
43 }
44
45 func (st *MysqlSessionStore) Delete(key interface{}) error {
46 st.lock.Lock()
47 defer st.lock.Unlock()
48 delete(st.values, key)
49 st.updatemysql()
50 return nil
51 }
52
53 func (st *MysqlSessionStore) SessionID() string {
54 return st.sid
55 }
56
57 func (st *MysqlSessionStore) updatemysql() {
58 b, err := encodeGob(st.values)
59 if err != nil {
60 return
61 }
62 st.c.Exec("UPDATE session set `session_data`= ? where session_key=?", b, st.sid)
63 }
64
65 func (st *MysqlSessionStore) SessionRelease() {
66 st.c.Close()
67 }
68
69 type MysqlProvider struct {
70 maxlifetime int64
71 savePath string
72 }
73
74 func (mp *MysqlProvider) connectInit() *sql.DB {
75 db, e := sql.Open("mysql", mp.savePath)
76 if e != nil {
77 return nil
78 }
79 return db
80 }
81
82 func (mp *MysqlProvider) SessionInit(maxlifetime int64, savePath string) error {
83 mp.maxlifetime = maxlifetime
84 mp.savePath = savePath
85 return nil
86 }
87
88 func (mp *MysqlProvider) SessionRead(sid string) (SessionStore, error) {
89 c := mp.connectInit()
90 row := c.QueryRow("select session_data from session where session_key=?", sid)
91 var sessiondata []byte
92 err := row.Scan(&sessiondata)
93 if err == sql.ErrNoRows {
94 c.Exec("insert into session(`session_key`,`session_data`,`session_expiry`) values(?,?,?)", sid, "", time.Now().Unix())
95 }
96 var kv map[interface{}]interface{}
97 if len(sessiondata) == 0 {
98 kv = make(map[interface{}]interface{})
99 } else {
100 kv, err = decodeGob(sessiondata)
101 if err != nil {
102 return nil, err
103 }
104 }
105 rs := &MysqlSessionStore{c: c, sid: sid, values: kv}
106 return rs, nil
107 }
108
109 func (mp *MysqlProvider) SessionDestroy(sid string) error {
110 c := mp.connectInit()
111 c.Exec("DELETE FROM session where session_key=?", sid)
112 c.Close()
113 return nil
114 }
115
116 func (mp *MysqlProvider) SessionGC() {
117 c := mp.connectInit()
118 c.Exec("DELETE from session where session_expiry < ?", time.Now().Unix()-mp.maxlifetime)
119 c.Close()
120 return
121 }
122
123 func init() {
124 Register("mysql", mysqlpder)
125 }
1 package session
2
3 import (
4 "github.com/garyburd/redigo/redis"
5 )
6
7 var redispder = &RedisProvider{}
8
9 type RedisSessionStore struct {
10 c redis.Conn
11 sid string
12 }
13
14 func (rs *RedisSessionStore) Set(key, value interface{}) error {
15 _, err := rs.c.Do("HSET", rs.sid, key, value)
16 return err
17 }
18
19 func (rs *RedisSessionStore) Get(key interface{}) interface{} {
20 v, err := rs.c.Do("GET", rs.sid, key)
21 if err != nil {
22 return nil
23 }
24 return v
25 }
26
27 func (rs *RedisSessionStore) Delete(key interface{}) error {
28 _, err := rs.c.Do("HDEL", rs.sid, key)
29 return err
30 }
31
32 func (rs *RedisSessionStore) SessionID() string {
33 return rs.sid
34 }
35
36 func (rs *RedisSessionStore) SessionRelease() {
37 rs.c.Close()
38 }
39
40 type RedisProvider struct {
41 maxlifetime int64
42 savePath string
43 }
44
45 func (rp *RedisProvider) connectInit() redis.Conn {
46 c, err := redis.Dial("tcp", rp.savePath)
47 if err != nil {
48 return nil
49 }
50 return c
51 }
52
53 func (rp *RedisProvider) SessionInit(maxlifetime int64, savePath string) error {
54 rp.maxlifetime = maxlifetime
55 rp.savePath = savePath
56 return nil
57 }
58
59 func (rp *RedisProvider) SessionRead(sid string) (SessionStore, error) {
60 c := rp.connectInit()
61 if str, err := redis.String(c.Do("GET", sid)); err != nil || str == "" {
62 c.Do("SET", sid, sid, rp.maxlifetime)
63 }
64 rs := &RedisSessionStore{c: c, sid: sid}
65 return rs, nil
66 }
67
68 func (rp *RedisProvider) SessionDestroy(sid string) error {
69 c := rp.connectInit()
70 c.Do("DEL", sid)
71 return nil
72 }
73
74 func (rp *RedisProvider) SessionGC() {
75 return
76 }
77
78 func init() {
79 Register("redis", redispder)
80 }
1 package session
2
3 import (
4 "crypto/rand"
5 "encoding/base64"
6 "fmt"
7 "io"
8 "net/http"
9 "net/url"
10 "time"
11 )
12
13 type SessionStore interface {
14 Set(key, value interface{}) error //set session value
15 Get(key interface{}) interface{} //get session value
16 Delete(key interface{}) error //delete session value
17 SessionID() string //back current sessionID
18 SessionRelease() // release the resource
19 }
20
21 type Provider interface {
22 SessionInit(maxlifetime int64, savePath string) error
23 SessionRead(sid string) (SessionStore, error)
24 SessionDestroy(sid string) error
25 SessionGC()
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 provider " + name)
39 }
40 provides[name] = provide
41 }
42
43 type Manager struct {
44 cookieName string //private cookiename
45 provider Provider
46 maxlifetime int64
47 }
48
49 func NewManager(provideName, cookieName string, maxlifetime int64, savePath string) (*Manager, error) {
50 provider, ok := provides[provideName]
51 if !ok {
52 return nil, fmt.Errorf("session: unknown provide %q (forgotten import?)", provideName)
53 }
54 provider.SessionInit(maxlifetime, savePath)
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 SessionStore) {
60 cookie, err := r.Cookie(manager.cookieName)
61 if err != nil || cookie.Value == "" {
62 sid := manager.sessionId()
63 session, _ = manager.provider.SessionRead(sid)
64 cookie := http.Cookie{Name: manager.cookieName, Value: url.QueryEscape(sid), Path: "/", HttpOnly: true, MaxAge: int(manager.maxlifetime)}
65 http.SetCookie(w, &cookie)
66 } else {
67 sid, _ := url.QueryUnescape(cookie.Value)
68 session, _ = manager.provider.SessionRead(sid)
69 }
70 return
71 }
72
73 //Destroy sessionid
74 func (manager *Manager) SessionDestroy(w http.ResponseWriter, r *http.Request) {
75 cookie, err := r.Cookie(manager.cookieName)
76 if err != nil || cookie.Value == "" {
77 return
78 } else {
79 manager.provider.SessionDestroy(cookie.Value)
80 expiration := time.Now()
81 cookie := http.Cookie{Name: manager.cookieName, Path: "/", HttpOnly: true, Expires: expiration, MaxAge: -1}
82 http.SetCookie(w, &cookie)
83 }
84 }
85
86 func (manager *Manager) GC() {
87 manager.provider.SessionGC()
88 time.AfterFunc(time.Duration(manager.maxlifetime)*time.Second, func() { manager.GC() })
89 }
90
91 func (manager *Manager) sessionId() string {
92 b := make([]byte, 24)
93 if _, err := io.ReadFull(rand.Reader, b); err != nil {
94 return ""
95 }
96 return base64.URLEncoding.EncodeToString(b)
97 }
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!