在開發網站的時候,有時候也會用到 sessions 來記錄狀態。 在這裡我們可以使用 github.com/gorilla/sessions 套件來輕鬆管理 sessions。

說明

github.com/gorilla/sessions 提供兩種 session 管理的方式。

  1. 將 session 存在 server 的方式。
  2. 將 session 跟著加密的 cookie 存放在 client side 的方式。

今天會介紹第 2 種方式,第 2 種方式的優點是 server 端不用管理 session 的狀態, server 就算重開,session 也會存在,不用擔心消失。 但是缺點也是有的,因為 session 是跟著 cookie stores 走的,所以當資料量大的時候,這種方式是不適合的,以現在 chrome 來說,就有限制 4096 bytes 的大小。

其他詳細優缺點說明可以參考 Cookie Store Sessions

範例

下面的程式碼我實做了三個頁面

  1. /home 存取頁面,要登入才會顯示正確訊息
  2. /login 模擬登入頁面,存入 session
  3. /logout 模擬登出頁面,把狀態修改成未登入
http-session
  • go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
package main

import (
"fmt"
"github.com/gorilla/sessions"
"log"
"net/http"
)

var store *sessions.CookieStore

func init() {
store = sessions.NewCookieStore([]byte("secret-key"))
}

func main() {
http.HandleFunc("/home", home)
http.HandleFunc("/login", login)
http.HandleFunc("/logout", logout)
fmt.Println("session server run on port 8080")
log.Fatal(http.ListenAndServe("localhost:8080", nil))
}

func logout(w http.ResponseWriter, r *http.Request) {
session, err := store.Get(r, "session-name")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
session.Values["auth"] = nil
err = session.Save(r, w)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
fmt.Fprintln(w, "logged out.")
}

func login(w http.ResponseWriter, r *http.Request) {
session, err := store.Get(r, "session-name")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
session.Values["auth"] = true
err = session.Save(r, w)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

fmt.Fprintln(w, "logged in")
}

func home(w http.ResponseWriter, r *http.Request) {
session, err := store.Get(r, "session-name")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
auth := session.Values["auth"]
if auth != nil {
isAuth, ok := auth.(bool)
if ok && isAuth {
fmt.Fprintln(w, "Home Page")
}else{
http.Error(w, "unauthorizeed", http.StatusUnauthorized)
return
}
}else{
http.Error(w, "unauthorizeed", http.StatusUnauthorized)
return
}

}

上面程式碼執行後,當存取 /home 的時候會看到,會看到沒有權限。

home without loginhome without login

所以我們先模擬登入login,登入之後,會看到有一個 Cookie Store Sessions 被建立了,且該 cookie 是加密過後的。

loginlogin

這時候再存取 /home 就可以看到有權限的畫面了。

home with loginhome with login

小結

最後要注意,session 也要加入過期時間,否則認證會一直有效。或者是可以設定 store.MaxAge() 設定 cookie 存在時間,時間到了 cookie 會自行刪除。 以及,如果要做 session key 的 rotation,可以參考 sessions#NewCookieStore

延伸閱讀

[gorillatoolkit-sessions]
[Golang Gorilla Sessions]