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链接
posted @ 2021-12-10 15:48  专职  阅读(156)  评论(0编辑  收藏  举报