gin框架中的會話控制
阿新 • • 發佈:2021-12-10
Cookie介紹
- Http協議是無狀態的,伺服器不能記錄瀏覽器的訪問狀態,也就是說伺服器不能判斷請求的客戶端是否已經登入
- Cookie就是解決http協議無狀態的方案之一
- Cookie實際上就是伺服器儲存在瀏覽器上的一小段文字資訊,瀏覽器有了Cookie之後,每次向伺服器傳送請求時都會同時將該資訊傳送給伺服器,伺服器收到請求後,就可以根據該資訊處理請求
- Cookie由伺服器建立,併發送給瀏覽器,最終由瀏覽器進行儲存
cookie的用途:
測試服務端傳送cookie給客戶端,客戶端請求時攜帶cookie
Cookie的使用
測試服務端傳送cookie給客戶端,客戶端請求時攜帶cookie
func someCookie(context *gin.Context) { cookie, err := context.Cookie("key_cookie") if err != nil { // 給客戶端設定cookie context.SetCookie( "key_cookie", "value_cookie", 60, // maxAge int, 單位為秒 "/", // path,cookie所在目錄 "127.0.0.1", // domain string,域名 false, // secure 是否智慧通過https訪問 false, // httpOnly bool 是否允許別人通過js獲取自己的cookie ) } fmt.Println("cookie的值是:", cookie) }
Cookie的練習
-
模擬實現許可權驗證中介軟體
- 有2個路由,login和home
- login用於設定cookie
- home是訪問檢視資訊的請求
- 在請求home之前,先跑中介軟體程式碼,檢驗是否存在cookie
-
訪問home,會顯示錯誤,因為許可權校驗未通過
-
然後訪問登入的請求,登入並設定cookie
-
再次訪問home,訪問成功
- 認證中介軟體程式碼
func AuthMiddleware() gin.HandlerFunc { return func(context *gin.Context) { // 獲取客戶端cookie並校驗 if cookie, err := context.Cookie("username"); err == nil { if cookie == "mayanan" { context.Next() return } } // 返回錯誤 context.JSON(http.StatusUnauthorized, gin.H{"data": "認證失敗"}) // 若認證失敗,不用呼叫後續的函式處理 context.Abort() return } }
- 處理請求函式
func someLogin(context *gin.Context) { context.SetCookie( "username", "mayanan", 60, // maxAge int, 單位為秒 "/", // path,cookie所在目錄 "127.0.0.1", // domain string,域名 false, // secure 是否智慧通過https訪問 false, // httpOnly bool 是否允許別人通過js獲取自己的cookie ) context.JSON(200, "登入成功") } func someHome(context *gin.Context) { context.JSON(200, gin.H{"data": "home"}) }
- 路由設定
router.GET("/some-login", someLogin)
router.GET("/some-home", middleware.AuthMiddleware(), someHome)
Cookie的缺點
- 不安全,明文
- 增加頻寬消耗
- 可以被禁用
- cookie有上限
Sessions
gorilla/sessions為自定義session後端提供cookie和檔案系統session以及基礎結構。
github連結
主要功能是:
簡單的API:將其用作設定簽名(以及可選的加密)cookie的簡便方法。
內建的後端可將session儲存在cookie或檔案系統中。
Flash訊息:一直持續讀取的session值。
切換session永續性(又稱“記住我”)和設定其他屬性的便捷方法。
旋轉身份驗證和加密金鑰的機制。
每個請求有多個session,即使使用不同的後端也是如此。
自定義session後端的介面和基礎結構:可以使用通用API檢索並批量儲存來自不同商店的session。
基於session實現上面的練習
- session-login session-home
func sessionLogin(context *gin.Context) {
// 初始化一個cookie儲存物件
// mayanan.cn是一個自己的祕鑰
var store = sessions.NewCookieStore([]byte("mayanan.cn"))
// 獲取一個session物件,session-name是session的名字
session, err := store.Get(context.Request, "session-name")
if err != nil {
fmt.Println(err)
return
}
// 在session中儲存值
session.Values["foo"] = "bar"
session.Values[42] = 43
// 儲存更改 session預設過期時間:一個月
session.Save(context.Request, context.Writer)
context.JSON(http.StatusOK, "登入成功")
}
func sessionHome(context *gin.Context) {
context.JSON(200, gin.H{"data": "sessionHome"})
}
- 中介軟體獲取session,如果解析失敗,攔截請求
func AuthMiddlewareSession() gin.HandlerFunc {
var store = sessions.NewCookieStore([]byte("mayanan.cn"))
return func(context *gin.Context) {
session, err := store.Get(context.Request, "session-name")
if err != nil {
context.JSON(http.StatusUnauthorized, gin.H{"err": err})
context.Abort() // 結束後續的請求處理
return
}
fooInfo := session.Values["foo"]
age := session.Values[42]
if fooInfo == "bar" && age == 43 {
context.Next()
return
}
context.JSON(http.StatusUnauthorized, gin.H{
"err": "身份認證失敗",
})
context.Abort()
return
}
}
- 路由配置
router.GET("/session-login", sessionLogin)
router.GET("/session-home", middleware.AuthMiddlewareSession(), sessionHome)
- 刪除session值
將session的最大儲存時間設定為小於零的數即為刪除
session.Options.MaxAge = -1
session.Save(r, w)
案例:
func sessionDelete(context *gin.Context) {
story := sessions.NewCookieStore([]byte("mayanan.cn"))
session, err := story.Get(context.Request, "session-name")
if err != nil {
context.JSON(http.StatusUnauthorized, err.Error())
context.Abort()
return
}
session.Options.MaxAge = -1
session.Save(context.Request, context.Writer)
context.String(200, "session刪除成功")
}