gin会话控制

一. 会话控制

        1.1 介绍

  • HTTP是无状态的协议,不会记录用户的任何信息,服务器也不能记录浏览器的访问状态,也就是说服务器不能区分两次请求是否是同一个客户端发出的。
  • Cookie是解决HTTP协议无状态的方案之一
  • Cookie实际就是服务器保存在浏览器上的一段信息。浏览器有了Cookie之后,每次向服务器发送请求时,都会同时将该信息发送给服务器,服务器收到请求后,就可以根据该信息处理请求。
  • Cookie由服务器创建,并发送给浏览器,最终由浏览器保存。

        1.2 Cookie用途

  • 服务器发送Cookie给客户端,客户端发送请求时携带Cookie

        1.3 Cookie使用

  • gin.Context的SetCookie方法可以用来设置Cookie
  • SetCookie将Set-Cookie表头添加到ResponseWrite的标头中。提供的cookie必须有一个有效的名称,无效的cookie可能会被无提示删除。
// SetCookie adds a Set-Cookie header to the ResponseWriter's headers.
// The provided cookie must have a valid Name. Invalid cookies may be
// silently dropped.
func (c *Context) SetCookie(name, value string, maxAge int, path, domain string, secure, httpOnly bool) {if path == "" {path = "/"}http.SetCookie(c.Writer, &http.Cookie{Name:     name,Value:    url.QueryEscape(value),MaxAge:   maxAge,Path:     path,Domain:   domain,SameSite: c.sameSite,Secure:   secure,HttpOnly: httpOnly,})
}
  • 参数
    • name:cookie的key
    • value:cookie的value
    • maxAge:过期时间,如果只想设置Cookie的保存路径而不想设置存活时间,可以在第三个参数中传nil
    • path:cookie的路径
    • domain:cookie路径作用域,本地调试配置成localhost,正式上线配成域名
    • secure:为true时,cookie在HTTP中无效,在HTTPS中有效
    •  httpOnly:是微软对 COOKIE 做的扩展。如果在 COOKIE 中设置了 “httpOnly” 属性,则通过程序(JS 脚本、 applet 等)将无法读取到 COOKIE 信息,防止 XSS 攻击产生。
  • 获取Cookie,通过gin.Context的Cookie方法
package mainimport ("fmt""github.com/gin-gonic/gin"
)func main() {r := gin.Default()r.GET("cookie", func(c *gin.Context) {//获取客户端是否携带cookiecookie, err := c.Cookie("key_cookie")if err != nil {cookie = "NoCookie"//给客户端设置cookie//maxAge 单位为秒c.SetCookie("key_cookie", "val_cookie", 60, "/", "localhost", false, true)}fmt.Println("cookie: ", cookie)})r.Run()
}

        1.4 Cookie练习

  • 模拟实现权限验证中间件
    • 两个路由login和home
    • login用于设置cookie
    • home处理请求返回响应
    • 在请求home前,先跑中间件代码,检验是否存在cookie
package mainimport ("net/http""github.com/gin-gonic/gin"
)func MiddleWare() gin.HandlerFunc {return func(c *gin.Context) {//获取cookiecookie, err := c.Cookie("key_cookie")if err != nil {c.JSON(http.StatusUnauthorized, gin.H{"status": "fail", "err": err.Error()})//验证不通过,不在调用后续函数处理c.Abort()return}if cookie != "val_cookie" {c.JSON(http.StatusBadRequest, gin.H{"status": "fail", "err": "err cookie"})//验证不通过,不在调用后续函数处理c.Abort()return}//执行路由处理代码c.Next()}
}func main() {r := gin.Default()r.GET("/login", func(c *gin.Context) {//设置cookiec.SetCookie("key_cookie", "val_cookie", 60, "/", "127.0.0.1", false, true)c.String(http.StatusOK, "Login success")})r.GET("/home", MiddleWare(), func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"data": "home"})})r.Run()
}

演示:

        1.5 Cookie缺点

  •  不安全,明文发送
  • 增加带宽消耗
  • 可以被禁用
  • cookie有上限

        1.6 Session

        在web开发中,大家一定会使用到session。在go框架中并没有集成session管理的中间件。要想使用session功能。可以使用gorilla/sessions这个包。

                1.6.1 什么是session

        session就是用来在服务端存储相关数据的,以便在同一个用户多次请求之间保存用户的状态,比如登录状态。因为HTTP协议是无状态的,不记录用户的信息,使用cookie的缺点不安全,明文发送,而session通过使用标识,也就是所谓的sessionid来解决cookie的不安全的缺点。

        该sessionid有服务器生成,并存储在客户端的cookie或者url中。当客户端再次发送请求时,会携带该标识,服务端可以通过该标识查找到存在服务器上的相关数据。

        原理如下:

                1.6.2 gorilla/sessions包 

        gorilla/sessions包提供了将session数据存储与cookie和文件中的功能。同时还支持自定义后端存储,比如将session数据存储与redis,mysql等等。

        使用下面命令安装:

go get github.com/gorilla/sessions

                1.6.3 基本使用 

        该包的使用可以分为五步:定义存储session的变量,程序启动时实例化具体的session存储类型,读取或存储数据到session,持久化session。

package mainimport ("log""net/http""github.com/gin-gonic/gin""github.com/gorilla/sessions"
)// 第一步:定义全局的存储session数据变量
var sessionStore sessions.Storefunc main() {r := gin.Default()//第二步:程序启动后,指定具体的存储数据类型:redis,mysql或文件//这里指定的是文件sessionStore = sessions.NewFilesystemStore(".", []byte("Hello"))r.GET("/save", func(c *gin.Context) {//第三步:在具体的handler中获取session//Get() 总是返回一个sessionsession, err := sessionStore.Get(c.Request, "sessionid")if err != nil {log.Println(err.Error())}//第四步:从session中存储或取出数据session.Values["userid"] = "123123"//第五步保存session数据,本质上是将内存中的数据持久化到存储介质中//本例是持久化到文件中session.Save(c.Request, c.Writer)c.JSON(http.StatusOK, gin.H{"status": "ok",})})r.GET("/get", func(c *gin.Context) {session, err := sessionStore.Get(c.Request, "sessionid")if err != nil {c.JSON(http.StatusInternalServerError, gin.H{"status": "false","err":    err.Error(),})}userid := session.Values["userid"]c.JSON(http.StatusOK, gin.H{"message": userid,"status":  "ok",})})r.Run()
}

        在该示例中,第一步的sessions.Store本质是一个接口类型,只要实现了该接口,就可以存储session数据。在第二步中就指定了具体存储类型:文件类型。返回的session的类型为*sessions.FilesystemStore,实现了session.Store接口。

        在第三步获取session时,Store.Get有两个参数,一个是请求参数request,一个是session-name,存储于cookie或url中,当然也可以是在Header中。服务端从request中通过该参数名获取session-id,在通过session-id从后端存储中(文件,redis或mysql等)获取对应的数据,则读取出来并解析到session对象中,否则就初始化一个新的session对象。

        第五步本质上是持久化。因为在第四步只是将数据保存到内存中,需要调用Save才能持久化到对应的存储介质。

        演示:

目录结构:

客户端:

        服务器多出来的session文件内容是一个加密字符串。

                1.6.4 实现原理

        session的存储本质上就是在服务端给每一个用户存储一行记录。服务端给每个用户分配一个唯一的session-id,以session-id为主键,存储对应的值。如果存储在mysql中,sessioin-id就是主键;如果存储在redis中,session-id就是key;如果存储在文件中,session-id就是对应的文件名,文件内容就是存储的session数据。

 cookie和session原理:        

我们拿登录账号举例:

        我们知道http协议是无状态的,并不会记录用户的信息。但是我们实际生活中使用网页需要登录时,一般我们登录了一次,之后并不会需要再登录了。

        这是因为http本身是无状态的,但是如果访问某资源频繁需要登录,会导致用户的体验不好。

cookie原理:

        于是当浏览器访问某资源需要登录时,客户端将name和passwd发送个服务器,服务器与注册时保存的name和passwd对比,成功后响应,将name和passwd放在报头的set-cookie中发送给客户端,客户端将其保存到cookie中,下次访问时,将cookie信息发送给服务器,就不需要登录了。

        cookie本质是一个浏览器的文件,里面保存用户的一些信息。

        文件保存分为内存级(关闭浏览器进程就空间释放了),硬盘级文件(长时间保存在硬盘中,关闭进程并不会释放)。

        但是:直接发送cookie,cookie保存的name和passwd并不安全,中间人可以直接获得用户的name和passward。

session原理:

        在本地保存用户的信息,发送的时候不安全。于是,在客户端登录时,将name和passwd发送给服务器,服务器形成一个文件session,里面有一个标识sid,全互联网唯一,标识的是用户的信息,响应时将sid放到set-cookie里发送给客户端,客户端将sid保存到cookie中,下一次访问带有的cookie中保存的是sid,服务器只要拿着sid比较即可。

        这样用户信息保存到了服务器,相比较只使用cookie安全性会高一点。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/38447.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2010-2022年 政府透明度指数报告整理

政府透明度指数报告是衡量政府透明度的重要工具,它由独立的评估机构或研究机构发布,用以反映政府在不同方面的表现。以下是对政府透明度指数报告的详细介绍: 数据简介 定义:政府透明度指数报告衡量的是政府在信息公开、政策制定…

Linux——/etc/passwd文件含义,grep,cut

/etc/passwd文件含义 作用 - 记录用户账户信息:共分为7段,使用冒号分割 含义 - 文件内容意义:账户名:密码代号x:UID:GID:注释:家目录:SHELL - 第7列/sbin/nologin&#x…

无人机赋能自然资源调查

确权 业务挑战 由于测绘人员难以到达现场,确权区域大,传统人工测绘覆盖 不全面,信息不完整 传统测绘成果单一,现场核实难度高,确权采集信息不对称 无人机优势 数据采集效率是人工的10倍以上,可自动将…

分布式限流:Spring Cloud Gateway 限流

分布式限流:Spring Cloud Gateway 限流 在现代微服务架构中,流量控制是一个至关重要的部分。分布式限流作为一种有效的流量控制手段,能够帮助我们保护系统不被突发的流量冲垮。Spring Cloud Gateway支持多种限流方式。 什么是分布式限流 分…

vivado VIO IP核

参考:pg159 VIO:可以模拟输入/输出功能,实时监视和修改FPGA中的信号,用于调试和验证,与ILA相比,VIO无需占用RAM资源。 VIO IP的输出对于FPGA内部逻辑是输入信号,可以在调试界面设置输入值&…

分享屏幕坐标和窗口通信

简介 实现功能&#xff0c;通过url传参选择扑克牌&#xff0c;桌面同时打开两个以上该窗口&#xff0c;扑克牌可以在窗口之间移动。 在线演示 屏幕坐标和窗口通信 实现代码 <!DOCTYPE html><html><head> <meta http-equiv"Content-Type" co…

html--橙色火箭404维护

<!DOCTYPE html> <html> <head><meta charset"UTF-8"><title>系统维护通知</title><link rel"stylesheet" type"text/css" href"css/notice.css"/> </head> <body><div cla…

代码随想录——柠檬水找零(Leetcode860)

题目链接 贪心 class Solution {public boolean lemonadeChange(int[] bills) {if(bills[0] 10 || bills[0] 20 || bills[1] 20){return false;}int count5 1;int count10 0;for(int i 1; i < bills.length; i){if(bills[i] 5){count5;}if(bills[i] 10){count10;…

Geeker-Admin:现代化的开源后台管理框架

Geeker-Admin&#xff1a;优雅管理&#xff0c;高效开发&#xff0c;尽在Geeker-Admin- 精选真开源&#xff0c;释放新价值。 概览 Geeker-Admin是一个基于Vue 3.4、TypeScript、Vite 5、Pinia和Element-Plus构建的开源后台管理框架。它为开发者提供了一套现代化、响应式的管理…

vue3的配置和使用

vue的使用需要配置node且node版本需要在15以上。管理员方式打开cmd&#xff0c;输入node -v&#xff0c;可以查看node版本。 创建vue有以下两种方式 npm init vuelatestnpm create vuelatest创建后输入项目名&#xff0c;其它的输入否即可&#xff0c;新手可以先不用 按照要求…

【01最短路 BFS】1368. 使网格图至少有一条有效路径的最小代价

如果有不明白的&#xff0c;请加文末QQ群。 本文涉及知识点 01最短路 CBFS算法 图论知识汇总 LeetCode 1368. 使网格图至少有一条有效路径的最小代价 给你一个 m x n 的网格图 grid 。 grid 中每个格子都有一个数字&#xff0c;对应着从该格子出发下一步走的方向。 grid[i]…

利用谷歌云serverless代码托管服务Cloud Functions构建Gemini Pro API

谷歌在2024年4月发布了全新一代的多模态模型Gemini 1.5 Pro&#xff0c;Gemini 1.5 Pro不仅能够生成创意文本和代码&#xff0c;还能理解、总结上传的图片、视频和音频内容&#xff0c;并且支持高达100万tokens的上下文。在多个基准测试中表现优异&#xff0c;性能超越了ChatGP…

【机器学习】Python sorted 函数

目录&#xff1a; 什么是sorted()函数列表降序排序应用到字符串自定义排序规则实际应用 Python中的内置函数——sorted()。 1. 什么是sorted()函数 在Python中&#xff0c;sorted()是一个内置函数&#xff0c;用于对任何可迭代对象&#xff08;如列表、元组、字符串等&…

AliyunOS安装Node.js

方法1&#xff1a;dnf软件包安装工具自动安装 最方便的安装方式是通过系统的dnf工具&#xff0c;我测试使用的AliyunOS的版本是Alibaba Cloud Linux 3.2104&#xff0c;具体流程如下&#xff1a; dnf module list nodejs #列出服务器中可以使用的所有nodejs版本确定下来希望安…

【折腾手机】一加6T刷机postmarketOS经历和体验

写在前面 到目前为止&#xff0c;我已经花了非常多的时间去学习和了解x86架构和RISC-V架构&#xff0c;对它们的指令集编程、指令格式的设计、编译套件的使用都亲自去体会和实践过&#xff0c;学到了很多的东西。但是对于离我们最近的arm架构却了解甚少。为什么说离我们最近呢…

2095.删除链表的中间节点

给你一个链表的头节点 head 。删除链表的中间节点 &#xff0c;并返回修改后的链表的头节点 head。 长度为 n 链表的中间节点是从头数起第 ⌊n / 2⌋ 个节点&#xff08;下标从 0 开始&#xff09;&#xff0c;其中 ⌊x⌋ 表示小于或等于 x 的最大整数。 对于 n 1、2、3、4 和…

网络==>总论v4

既然是写ICT方面的文章&#xff0c;就要不断更新版本&#xff0c;不是文学&#xff0c;可以一劳永逸&#xff0c;如果不更新&#xff0c;看十年前或者二十年前的书意义不大&#xff0c;这就是为啥看到很多编程书都更新到第十几版了&#xff0c;因为要与时俱进。 在去一个地方旅…

51单片机第21步_将TIM0用作两个8位定时器同时将TIM1用作波特率发生器

本章重点讲解将TIM0用作两个8位定时器&#xff0c;同时将TIM1用作波特率发生器。 当定时器T0在方式3时&#xff0c;T1不能产生中断&#xff0c;但可以正常工作在方式0、1、2下&#xff0c;大多数情况下&#xff0c;T1将用作串口的波特率发生器。 1、定时器0工作在模式3框图&a…

Webpack: 核心配置结构

概述 Webpack 是一种 「配置」 驱动的构建工具&#xff0c;所以站在应用的角度&#xff0c;必须深入学习 Webpack 的各项配置规则&#xff0c;才能灵活应对各种构建需求。本文将作为小册应用系列的一个总结&#xff0c;汇总与应用配置相关的各项知识点&#xff0c;包括&#x…

高并发场景下的热点key问题探析与应对策略

目录 一、问题描述 二、发现机制 三、解决策略分析 &#xff08;一&#xff09;解决策略一&#xff1a;多级缓存策略 客户端本地缓存 代理节点本地缓存 &#xff08;二&#xff09;解决策略二&#xff1a;多副本策略 &#xff08;三&#xff09;解决策略三&#xff1a;热点…