1. 程式人生 > 其它 >gin框架中的會話控制

gin框架中的會話控制

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的練習

  • 模擬實現許可權驗證中介軟體

    1. 有2個路由,login和home
    2. login用於設定cookie
    3. home是訪問檢視資訊的請求
    4. 在請求home之前,先跑中介軟體程式碼,檢驗是否存在cookie
  • 訪問home,會顯示錯誤,因為許可權校驗未通過

  • 然後訪問登入的請求,登入並設定cookie

  • 再次訪問home,訪問成功

  1. 認證中介軟體程式碼
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
	}
}
  1. 處理請求函式
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"})
}
  1. 路由設定
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刪除成功")
}
  • session預設儲存到了簽名的cookie中了
  • 如果想儲存到mysql中:github連結
  • 儲存到redis中:github連結