Cookie使用详解

news2025/2/23 14:32:21

Cookie使用详解

目录

  • Cookie使用详解
    • 理论知识
      • 前言
      • 创建Cookie
      • cookie 的属性介绍
        • name 、value
        • domain
        • path
        • Expires 、Max-Age
        • SameSite
        • Secure,HttpOnly
      • Cookie与跨域、安全
      • 知识点小结
    • 实践
      • 相关配置修改
      • 代码实践
      • 实验过程记录
      • 其它
      • 小结

理论知识

前言

HTTP Cookie(也叫Web Cookie 或浏览器 Cookie)是服务器发送到用户浏览器并保存在本地的一小块数据。浏览器会存储 cookie 并在下次同一服务器再发起请求时携带并发送到服务器上。通常,它用于告知服务端两个请求是否来自同一浏览器——如保持用户的登录状态。Cookie使基于无状态的HTTP协议记录稳定的状态信息成为了可能。

Cookie 主要用于以下三个方面

  • 会话状态管理
    • 用户登录状态
    • 购物车
    • 游戏分数
  • 个性设置
    • 用户自定义设置
    • 主题
  • 浏览器行为跟踪
    • 跟踪分析用户行为

Cookie 曾用于客户端数据的存储,因为当时并没有其它合适的存储办法而作为唯一的存储手段,但现在出现了许多现代存储API。由于服务器指定Cookie后,浏览器的每次请求都会携带Cookie数据,会带来额外的性能开销。目前新型的浏览器API已经开始允许开发者直接将数据存储到本地,如使用localStoragesessionStorageindexedDB

创建Cookie

服务器收到HTTP请求后,服务器可以在相应标头里面添加一个或多个Set-Cookie选项。浏览器收到响应后通常会保存下Cookie,并将其放在HTTP Cookie标头内,向同一服务器发出请求时一起发送。可以指定域和路径设置额外的限制,以限制cookie发送的位置。

简单的说就是后端服务器可以在响应标头里面加上Set-Cookie这个特殊字段以及其值,让浏览器保存下来。

Set-CookieCookie标头

服务器使用Set-Cookie响应头部向用户代理(一般指浏览器)发送Cookie信息。一个简单的Cookie可能像这样子:

Set-Cookie: <cookie-name>=<cookie-value>

cookie 的属性介绍

name 、value

Cookie的内容信息,以 name=value的形式进行存储,区分大小写。

domain

domain属性指定浏览器发送HTTP请求时,哪些域名要附带这个Cookie。

可以设置domain为当前服务器域名或者父域名.如果未设置,则该Cookie值只能在发向该域名的请求时被携带。如果设置了domain,则发向该域以及子域的请求都会带上该Cookie.由于历史原因,存在前缀点的domain,有前缀点表示允许子域请求携带该cookie,无前缀点则不允许。目前规范规定忽略前缀点。

path

path指定浏览器发出HTTP请求时,哪些路径要附带这个Cookie。如果配置的时候设置了path,那么在该path下的子路径都允许携带该cookie

例如,设置Path=/docs,则以下地址都会匹配:

  • /docs
  • /docs/
  • /docs/Web

但是这些请求路径不会匹配以下地址:

  • /
  • /docsets
  • /api/docs

Expires 、Max-Age

这两个字段用于定义Cookie的生命周期。Expires是一个绝对时间,如果没有设置这个属性或者设置为null,则表示这是一个Session Cookie.需要注意的是,浏览器是根据本地时间与Expires对此判断是否过期,而本地时间是可能变动的,所以无法保证Cookie一定会在服务器指定的时间过期。

Max-Age是一个相对时间,是在Cookie失效之前需要经过的秒数。秒数为0或-1将会使Cookie直接过期。

那么要是当ExpiresMax-Age同时被设置时,Max-Age的值将头衔生效。如果都没有指定,那这个Cookie就是Session Cookie,一旦用户关闭浏览器,这个Cookie就会被删除。有些浏览器提供了绘画回复功能,这种情况下即使关闭了浏览器,Session Cookie也会被保留下来,就好像浏览器从来没有关闭一样,这会导致Cookie的生命周期无限期延长。

SameSite

SameSite Cookie允许服务器要求某个cookie在跨站请求时不会被发送,从而可以阻止跨站请求伪造攻击(CSRF).总共有三个值:Strict,Lax,None。现在默认为Lax,为None时必须具有Secure属性。

Secure,HttpOnly

Secure属性限制该Cookie只有在HTTPS协议下,才会被发送到服务器。若当前协议时HTTP,则浏览器会忽略服务器发来的Secure属性。

HttpOnly属性指定该Cookie无法通过javaScript脚本获取到,防止恶意脚本的攻击。

Cookie与跨域、安全

在发送跨域AJAX请求时,Cookie默认不会被发送。如果需要允许跨域请求携带Cookie,需要在发送请求的时候设置withCredentials请求头,服务端需要在请求相应中配置CORS相关头部(Allow-cross-with-credentials:true)。

特殊的情况是,如果AJAX请求配置了withCredentials,即使响应没有配置CORS响应标头而被浏览器拦截,响应中的set-cookie也会生效,可以成功种上Cookie

知识点小结

请求会携带Cookie的条件

  • domainpath属性与请求的域名路径匹配,Cookie才会被携带
  • 如果有Secure属性,请求协议必须时HTTPS
  • 跨域AJAX请求不会携带Cookie,如果需要携带需要配置withCredentials请求头以及CORS响应头。
  • 如果请求跨站了,还要判断SameSite属性是否满足发送条件。

实践

相关配置修改

这里讲的环境为Windows系统下

直接快捷键win + r,将C:\Windows\System32\drivers\etc\hosts输入其中。选择确定并选择用记事本打开。

在其中的空白行输入:

127.0.0.1	ywhabc.com

表示ywhabc.com映射了127.0.0.1.

设置的这个域名,与后面代码中设置Cookie时的domain属性相关

image-20221102093354950

现在我们就可以在本机上通过访问ywhabc.com而达到访问127.0.0.1达到相同的效果。

image-20221102100853066

代码实践

为了更好的理解,这个运行的机制。采用GO gin框架使用cookie写一个简单的模拟用户登录的功能。

案例目标功能:

  • 未登录时,无法成功进行其它请求
  • 有登录功能
  • 有登出功能
  • 用户登录后半小时内无请求操作,取消其登录

采用的工具:

  • go gin 框架
  • redis (基于docker创建)

操作Redis部分代码

这个之前一篇博客有记录过,不细讲。下面没有对错误抛出进行正确处理。

package main

import (
	"context"
	"fmt"
	"sync"
	"time"

	"github.com/go-redis/redis/v8"
)

var (
	ctx             = context.Background()
	linkRedisMethod sync.Once
	DbRedis         *redis.Client
)

func init() {
	initRedis()
}

// 连接redis数据库
// 且只会执行一次
func initRedis() {
	linkRedisMethod.Do(func() {
		//连接数据库
		DbRedis = redis.NewClient(&redis.Options{
			Addr:     "127.0.0.1:6379", // 对应的ip以及端口号
			Password: "",               // 数据库的密码
			DB:       0,                // 数据库的编号,默认的话是0
		})
		// 连接测活
		_, err := DbRedis.Ping(ctx).Result()
		if err != nil {
			panic(err)
		}
		fmt.Println("连接Redis成功")
	})
}

// 登录成功时写入登录标记
func InsertLoginFlag(key, value string, timeout time.Duration) {
	err := DbRedis.Set(ctx, key, value, timeout).Err()
	if err != nil {
		fmt.Println(err.Error())
	}
	fmt.Println("insert successfully")
}

// 检查用户是否登录
func CheckLoginFlag(key string) int {
	_, err := DbRedis.Get(ctx, key).Result()
	if err == redis.Nil {
		return 0
	} else if err != nil {
		return -1
	}
	return 1
}

// 用户登出时删除登录记录
func DelLoginFlag(key string) {
	err := DbRedis.Del(ctx, key)
	if err != nil {
		fmt.Println(err)
	}
}

// 更新用户的登录状态
func UpdateLoginFlag(key string) {
	DbRedis.Expire(ctx, key, time.Minute*30)
}

路由部分主体代码

这部分代码主要是用了中间件对用户登录状态进行验证,阻止用户进行非法请求。同时登录、登出、登录成功的测试部分包括了对cookie的设置和验证。

package main

import (
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
)

// 检验用户是否登录的中中间件
func authorVriFMiddle(c *gin.Context) {
	if c.Request.URL.Path == "/api/login" {
		c.Next()
		return
	}
	cookieKey, err := c.Cookie(LOGINNAME)
	// 若有cookie就去数据库中检查确认是否登录
	loginState := CheckLoginFlag(cookieKey)

	if err != nil || loginState == 0 || loginState == -1 {
		c.JSON(http.StatusUnauthorized, gin.H{"message": "访问未授权"})
		c.Abort()
	} else {
		// 如果收到已登录用户的请求,那么就更新已登录用户的登录状态
		if c.Request.URL.Path != "/api/logout" {
			UpdateLoginFlag(cookieKey)
		}
		c.Next()
	}
}

// 用于检验未登录能否获得数据
func testIsLogin(c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{
		"msg": "Hello",
	})
}

// 用户登录接口
func UserLogin(c *gin.Context) {
	data := make(map[string]interface{})
	c.BindJSON(&data)
	userName := data["username"].(string)
	// password := data["password"].(string)
	// Do something to check password
	// 向数据库中写入已登录标志, 过期时间为半小时
	InsertLoginFlag("login-"+userName, "ok", time.Minute*30)

	c.SetCookie(LOGINNAME, "login-"+userName, 110000, "/api", ".ywhabc.com", false, false)
	c.JSON(http.StatusOK, gin.H{
		"msg": "登录成功",
	})
}

// 用户登出接口
func UserLogout(c *gin.Context) {
	cookieKey, _ := c.Cookie(LOGINNAME)
	DelLoginFlag(cookieKey)
	c.SetCookie(LOGINNAME, "", -1, "/api", ".ywhabc.com", false, false)
	c.JSON(http.StatusOK, gin.H{
		"msg": "成功登出",
	})
}

func main() {
	router := gin.Default()
	t := router.Group("/api")
	t.Use(authorVriFMiddle)

	t.GET("/test", testIsLogin)

	t.POST("/login", UserLogin)

	t.GET("/logout", UserLogout)

	router.Run(":886")
}

实验过程记录

下面给出用Apifox模拟用户登录的截图记录(按操作顺序给出)

非法请求数据

image-20221102145223850

用户登录

image-20221102145438412

登录后请求数据

image-20221102145458620

用户登出

image-20221102145522107

验证登出

image-20221102145538045

其它

其实我们是可以看到,保存在浏览器上的Cookie的.例如Chorme浏览器。

image-20221102145842455

image-20221102150014934

然后搜索一下

image-20221102150057665

小结

本来是最近要做个cas登录项目的,里面用到了Cookie相关东西,所以先学习一下这个部分。

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

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

相关文章

使用Charles和iPhone进行微信小程序抓包详解

基于工作原因&#xff0c;需要对一款微信小程序进行测试。本次任务是纯黑盒方式&#xff0c;所以只有通过抓包的方式找到接口及参数列表&#xff0c;再逐一进行功能和性能测试。 一、使用工具 网络抓包工具&#xff1a;Charles 设备&#xff1a;iPhone6s&#xff0c;iPhone1…

数据分析 | Pandas 200道练习题,每日10道题,学完必成大神(8)

文章目录前期准备1. 将收盘价5日均线&#xff0c;20日均线与原始数据绘制在同一个图上2. 按周为采样规则&#xff0c;取一周收盘价的最大值3. 绘重制采样数据与原始数据4. 将数据往后移动5天、5. 将数据向前移动5天6. 使用expending函数计算开盘价的移动窗口的均值7. 绘制上一题…

牛客刷题系列(汽水瓶,跳台阶扩展问题,斐波那契凤尾)

牛客刷题系列一&#xff1a;汽水瓶题目链接常规写法简便写法二.跳台阶扩展问题三&#xff1a;斐波那契凤尾很多小伙伴为了刷题发愁 今天为大家推荐一款刷题神奇哦&#xff1a;刷题面试神器牛客 各大互联网大厂面试真题。从基础到入阶乃至原理刨析类面试题 应有尽有&#xff0c;…

云IDE介绍——CSDN开发云

云IDE产品介绍云IDE使用教程 免费使用地址&#xff1a;点击【云IDE】&#xff0c;即可开始创建工作空间啦~ 作者简介&#xff1a;一名在校云计算网络运维学生、每天分享网络运维的学习经验、和学习笔记。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xf…

【学习笔记之数据结构】时间复杂度与空间复杂度

一、算法效率 算法在编写成可执行程序后&#xff0c;运行时需要耗费时间资源和空间&#xff08;内存&#xff09;资源。因此衡量一个算法的好坏&#xff0c;一般是从时间和空间两个维度来衡量的&#xff0c;即时间复杂度和空间复杂度。   时间复杂度主要衡量一个算法的运行快…

2022年音视频面试题 C/C++/Linux/FFmpeg/webRTC/rtmp/hls/rtsp/ffplay/srs

1&#xff09;OpenGL 是按照什么架构设计的&#xff1f; OpenGL 的渲染架构是 Client/Server 模式&#xff1a;Client&#xff08;客户端&#xff09;指的是我们在 CPU 上运行的一些代码&#xff0c;比如我们会编写 OC/C/Java 代码调用 OpenGL 的一些 API&#xff1b;而 Server…

mybatis学习(1)

使用mybatis也是有一段时间了&#xff0c;但是一直没有系统了解和学习&#xff0c;最近正好有空&#xff0c;索性花点时间熟悉下。 为什么是mybatis&#xff1f; 了解mybatis之前&#xff0c;需要知道什么是"数据库持久层"&#xff0c;我的理解&#xff0c;就是将数…

Decoder与Encoder重要组件

Decoder与Encoder重要组件 大家知道&#xff0c;Netty从底层Java通道读到ByteBuf二进制数据&#xff0c;传入Netty通道的流水线&#xff0c;随后开始入站处理。在入站处理过程中&#xff0c;需要将ByteBuf二进制类型&#xff0c;解码成Java POJO对象。这个解码过程&#xff0c…

【Python基础篇020】网络编程初识

文章目录 &#x1f9a0;一、前言 &#x1f9a0;二、软件开发架构 &#x1f340;2.1、C/S架构 &#x1f340;2.2、B/S架构 &#x1f340;2.3、服务端与客户端 &#x1f9a0;三、ip与端口号 &#x1f340;3.1、IP地址与端口号常识 &#x1f340;3.2、MAC和IP的概念与不同…

实际应用效果不佳?来看看提升深度神经网络泛化能力的核心技术(附代码)

目录 数据增强 &#x1f4cc; 技术介绍 &#x1f4cc; 手动数据处理&增强 &#x1f4cc; 基于 TensorFlow 的数据增强 Dropout 随机失活 &#x1f4cc; 技术介绍 &#x1f4cc; 基于TensorFlow应用Dropout &#x1f4a1; L1 和 L2 正则化 &#x1f4cc; 技术介绍 …

Mybatis日志框架

文章目录一、 用日志打印代替sout1、sout有什么问题①问题1&#xff1a;I/O影响性能②问题2&#xff1a;无法统一管理③问题3&#xff1a;显得你很low2、使用日志框架的好处①设定级别&#xff0c;统一管理②灵活指定输出位置③自定义日志格式④基于日志分析问题二、最佳用法1、…

设计模式之【单例模式】全解,单例模式实现方式,暴力打破单例模式与解决方案,你真的认识单例模式吗?

文章目录什么是单例模式单例模式的应用场景处理有线程冲突的资源表示全局唯一类单例模式的实现方式1、饿汉式之静态常量2、饿汉式之静态代码块3、懒汉式之线程不安全方式&#xff08;不推荐&#xff09;4、懒汉式之加锁方式&#xff08;不推荐&#xff09;5、懒汉式之双重锁检查…

波司登的高端化后遗症

&#xff08;题图&#xff09; 文|螳螂观察 作者| 青月 受“三重”拉尼娜现象的影响&#xff0c;2022年冬天可能会因为阶段性冷空气的影响出现阶段性低温&#xff0c;且极端寒潮爆发的可能性大。 极端天气越来越多&#xff0c;年年冷冬&#xff0c;有望催化以羽绒服为代表的…

【uni-app从入门到实战】打包

小程序打包发布 1、小程序的打包发布很简单&#xff0c;只需要将程序运行到微信开发者工具中&#xff0c;然后点击右上角的上传按钮即可 我们这里的上传按钮不能点击是因为没有配置微信小程序AppID 打开项目的 manifest.json&#xff0c;选中微信小程序配置&#xff0c;填入微…

Java并发编程——线程间通信

线程间通信一、volatile 关键字二、等待/通知机制三、管道通信四、Thread.join一、volatile 关键字 为什么volatile关键字可以&#xff1f;因为之前说过了&#xff0c;此关键字能保证变量的可见性&#xff0c;也就是说变量一旦被修改&#xff0c;立马能被其他线程所感知 例子如…

拓端tecdat|R语言代做泰坦尼克号随机森林模型案例数据分析

全文链接&#xff1a;http://tecdat.cn/?p4281 原文出处&#xff1a;拓端数据部落公众号 视频&#xff1a;从决策树到随机森林&#xff1a;R语言信用卡违约分析信贷数据实例 从决策树到随机森林&#xff1a;R语言信用卡违约分析信贷数据实例&#xff0c;时长10:11 如果我们对…

Linux:环境变量

基本概念 环境变量一般是指在操作系统中用来指定操作系统运行环境的一些参数。 环境变量通常具有某些特殊用途&#xff0c;通常具有全局特性&#xff0c;可以被子进程继承下去 常见的环境变量 PATH : 指定命令的搜索路径 HOME : 指定用户的主工作目录(即用户登陆到Linux系统中…

[Linux]----文件操作(复习C语言+文件描述符)

文章目录前言一、基础概念二、回顾C语言2.1 对文件进行写操作2.2 追加写文件2.3 读文件2.4 简易cat功能总结stdin&stdout&stderr打开文件的方式三、系统文件I/O接口介绍open介绍使用open接口closewriteread四、文件描述符先验证0,1,2就是标准的IO标准输入流标准输出流标…

基于寄生-捕食算法的函数寻优算法

文章目录一、理论基础1、寄生-捕食算法&#xff08;1&#xff09;初始化&#xff08;2&#xff09;筑巢阶段(鸟窝)&#xff08;3&#xff09;寄生阶段(乌鸦-布谷鸟)&#xff08;4&#xff09;捕食阶段(乌鸦-猫)2、PPA算法伪代码二、仿真实验与结果分析三、参考文献一、理论基础…

QCC51XX---QACT用户指南

更新记录链接:QCC51XX---系统学习目录_嵌入式学习_force的博客-CSDN博客 QACT安装包不要放在有中文路径下,否则—直会安装报错。适用V7,V7.1 V7.2版本 打开QACT. 打开QACT. 点击 connection configuration 进去之后 点击1,然后点2,选择kalaccess.dll文件, workspace …