12-Gin的Cookie,Session.md

一 Cookie介绍和使用

扩展阅读:cookie,session,token

1.1 介绍

HTTP 是无状态协议。简单地说,当你浏览了一个页面,然后转到同一个网站的另一个页 面,服务器无法认识到这是同一个浏览器在访问同一个网站。每一次的访问,都是没有任何 关系的。如果我们要实现多个页面之间共享数据的话我们就可以使用 Cookie,Session或Token实 现

cookie 是存储浏览器中的键值对,可以让我们用同一个浏览器访问同一个域名 的时候共享数据

1.2 Gin中Cookie的设置

c.SetCookie(name, value string, maxAge int, path, domain string, secure,httpOnly bool)
// name:cookie的key值
// value:cookie的value值
// maxAge:过期时间,如果只想设置Cookie的保存路径而不想设置存活时间,可以设置为 nil
// path:cookie 的路径
// domain:cookie 的路径 Domain 作用域 本地调试配置成 localhost , 正式上线配置成域名
// secure:当 secure 值为 true 时,cookie 在 HTTP 中是无效,在 HTTPS 中 才有效
// httpOnly:是微软对 COOKIE 做的扩展。如果在 COOKIE 中设置了"httpOnly"属性,则通过程序(JS 脚本、applet 等)将无法读取到 COOKIE 信息,防止 XSS 攻击产生

1.3 Gin中Cookie的获取

cookie, err := c.Cookie("key值")

1.4 设置获取案例

package main

import (
   "fmt"
   "github.com/gin-gonic/gin"
)

func main() {
   r := gin.Default()
   r.GET("set_cookie", func(c *gin.Context) {
      c.SetCookie("name", "lqz", 60, "/", "", false, true)
      c.SetCookie("age", "19", 600, "", "", false, true)
      c.String(200, "cookie设置成功")
   })
   r.GET("get_cookie", func(c *gin.Context) {
      name, err := c.Cookie("name")
      if err != nil {
         c.String(200, "cookie获取打印失败,错误是:%s",err)
         return
      }
      fmt.Println("name的cookie值为:",name)
      c.String(200, "cookie获取打印成功")

   })
   r.Run(":8080")
}

1.5 Cookie登陆认证练习

  • 模拟实现权限验证中间件
    • 有2个路由,login和home
    • login用于设置cookie
    • home是访问查看信息的请求
    • 在请求home之前,先跑中间件代码,检验是否存在cookie
  • 访问home,会显示错误,因为权限校验未通过
package main

import (
	"github.com/gin-gonic/gin"
	"net/http"
)

func AuthMiddleWare() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 获取客户端cookie并校验
		if cookie, err := c.Cookie("login"); err == nil {
			if cookie == "yes" {
				c.Next()
			}
		} else {
			// 返回错误
			c.JSON(http.StatusUnauthorized, gin.H{"error": "没有登录"})
			// 若验证不通过,不再调用后续的函数处理
			c.Abort()
		}
	}
}

func main() {
	r := gin.Default()
	r.GET("/login", func(c *gin.Context) {
		c.SetCookie("login", "yes", 60, "/", "", false, true)
		// 返回信息
		c.String(200, "Login success!")
	})
	r.GET("/home", AuthMiddleWare(), func(c *gin.Context) {
		c.JSON(200, gin.H{"data": "登陆成功,能访问home"})
	})
	r.Run(":8080")
}

二 Session的介绍和使用

2.1 Session介绍

session 是另一种记录客户状态的机制,不同的是 Cookie 保存在客户端浏览器中,而 session 保存在服务器上。

2.2 Session工作流程

当客户端浏览器第一次访问服务器并发送请求时,服务器端会创建一个 session 对象,生成 一个类似于 key,value 的键值对,然后将 value 保存到服务器 将 key(cookie)返回到浏览器(客 户)端。浏览器下次访问时会携带 key(cookie),找到对应的 session(value)。

2.3 Gin中使用 Session

Gin 官方没有给我们提供 Session 相关的文档,这个时候我们可以使用第三方的 Session 中间 件来实现

推荐一:gin-contrib/sessions后起之秀

https://github.com/gin-contrib/sessions

推荐二:gorilla/sessions年久失修

https://github.com/gorilla/sessions

2.5 gin-contrib/sessions使用

下载:go get github.com/gin-contrib/sessions

2.5.1 session放在内存中

package main

import (
	"fmt"
	"github.com/gin-contrib/sessions"
	"github.com/gin-contrib/sessions/cookie"
	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()
	// 创建基于 cookie 的存储引擎,lqzisnb 参数是用于加密的密钥
	store := cookie.NewStore([]byte("lqzisnb"))
	// 设置 session 中间件,参数 sessionid,指的是 session 的名字,也是 cookie 的名字
	//store是前面创建的存储引擎,我们可以替换成其他存储引擎
	r.Use(sessions.Sessions("sessionid", store))
	r.GET("/set_session", func(c *gin.Context) {
		//初始化 session 对象
		session := sessions.Default(c) //设置过期时间
		// 过期时间6h
		session.Options(sessions.Options{MaxAge: 3600 * 6})
		//设置 Session
		session.Set("username", "lqz")
		session.Save()
		c.JSON(200, gin.H{"msg": "设置session成功----userrname:lqz"})
	})

	r.GET("/get_session", func(c *gin.Context) {
		session := sessions.Default(c)
		// 通过 session.Get 读取 session 值
		username := session.Get("username")
		fmt.Println(username)
		c.JSON(200, gin.H{"msg": "获取session成功"})
	})
	r.Run(":8080")

}

2.5.2 session放在redis中

如果我们想将 session 数据保存到 redis 中,只要将 session 的存储引擎改成 redis 即可。 使用 redis 作为存储引擎的例子,首先安装 redis 存储引擎的包

go get github.com/gin-contrib/sessions/redis

package main

import (
	"fmt"
	"github.com/gin-contrib/sessions"
	"github.com/gin-contrib/sessions/redis"
	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()
	// 初始化基于 redis 的存储引擎
	// size:redis 最大的空闲连接数
	//network: 数通信协议tcp或者udp
	//address:redis 地址, 格式,host:port
	//password:redis密码
	//最后一个参数:session 加密密钥
	store, _ := redis.NewStore(10, "tcp", "localhost:6379", "", []byte("secret"))
	r.Use(sessions.Sessions("sessionid", store))
	r.GET("/set_session", func(c *gin.Context) {
		session := sessions.Default(c)
		session.Options(sessions.Options{MaxAge: 3600 * 6})
		//设置 Session
		session.Set("username", "pyy")
		session.Save()
		c.JSON(200, gin.H{"msg": "设置session到reids成功----userrname:pyy"})
	})
	r.GET("/get_session", func(c *gin.Context) {
		session := sessions.Default(c)
		// 通过 session.Get 读取 session 值
		username := session.Get("username")
		fmt.Println(username)
		c.JSON(200, gin.H{"msg": "获取session成功"})
	})
	r.Run(":8080")
}

2.6 gorilla/sessions使用

go get github.com/gorilla/sessions

2.6.1 gin框架使用

package main

import (
   "fmt"
   "github.com/gin-gonic/gin"
   "net/http"

   "github.com/gorilla/sessions"
)

// 初始化一个cookie存储对象
// something-very-secret应该是一个你自己的密匙,只要不被别人知道就行
var store = sessions.NewCookieStore([]byte("asdfasdf"))

func main() {
   r:=gin.New()
   r.GET("/savesession", func(context *gin.Context) {
      // Get a session. We're ignoring the error resulted from decoding an
      // existing session: Get() always returns a session, even if empty.
      session, err := store.Get(context.Request, "session-name")
      if err != nil {
         context.String(http.StatusInternalServerError,"出错了")
         return
      }

      // 在session中存储值
      session.Values["name"] = "lqz"
      session.Values["age"] = 18
      session.Values[42] = 43
      // 保存更改
      session.Save(context.Request, context.Writer)
      context.String(200,"保存session成功")
   })
   r.GET("getsession", func(context *gin.Context) {
      session, err := store.Get(context.Request, "session-name")
      if err != nil {
         context.String(http.StatusInternalServerError,"出错了")
         return
      }
      name := session.Values["name"]
      age := session.Values["age"]
      count:=session.Values[42]
      fmt.Println(name)
      fmt.Println(age)
      fmt.Println(count)
      context.String(200,"查询成功")
   })
   r.Run()
}

2.6.2 net/http使用

package main

import (
    "fmt"
    "net/http"

    "github.com/gorilla/sessions"
)

// 初始化一个cookie存储对象
// something-very-secret应该是一个你自己的密匙,只要不被别人知道就行
var store = sessions.NewCookieStore([]byte("something-very-secret"))

func main() {
    http.HandleFunc("/save", SaveSession)
    http.HandleFunc("/get", GetSession)
    err := http.ListenAndServe(":8080", nil)
    if err != nil {
        fmt.Println("HTTP server failed,err:", err)
        return
    }
}

func SaveSession(w http.ResponseWriter, r *http.Request) {
    // Get a session. We're ignoring the error resulted from decoding an
    // existing session: Get() always returns a session, even if empty.

    // 获取一个session对象,session-name是session的名字
    session, err := store.Get(r, "session-name")
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }

    // 在session中存储值
    session.Values["foo"] = "bar"
    session.Values[42] = 43
    // 保存更改
    session.Save(r, w)
}
func GetSession(w http.ResponseWriter, r *http.Request) {
    session, err := store.Get(r, "session-name")
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    foo := session.Values["foo"]
    fmt.Println(foo)
}

2.6.3 删除session的值

// 删除
// 将session的最大存储时间设置为小于零的数即为删除
session.Options.MaxAge = -1
session.Save(r, w)
posted @ 2022-04-16 22:07  刘清政  阅读(504)  评论(0编辑  收藏  举报