Cookie 和 Session
- 一. Cookie
- 1. 什么是 Cookie
- 2. Cookie 的作用
- 3. Cookie 的组成
- 4. Cookie 的组织形式
- 5. Cookie 的传输
- 6. 如何提高 Cookie 的安全性
- 7. Cookie 类
- 二. Session
- 1. 理解会话机制 (Session)
- 2. Sessoin 的组织形式
- 3. HttpSession 类
- 三. Cookie 和 Session 的联系与区别
一. Cookie
1. 什么是 Cookie
Cookie(中文意思为 “曲奇饼,小甜饼”): 我们这里指一种小型文本文件,通常由网站服务器发送到用户的浏览器,然后存储在用户的计算机上。用于跟踪、识别和存储关于用户在网站上的活动和偏好的信息。
Cookie 就是浏览器给页面提供的一种能持久化存储数据的机制。
- 浏览器为了安全默认是不让网页访问用户电脑上的文件系统, 但是有时确实需要让页面存储一些数据,方便后续访问网站。
于是浏览器不让页面访问整个磁盘数据,但是单独给页面分配了一块空间,有多种不同的形式, Cookie 是最经典的形式。
2. Cookie 的作用
服务器将 Cookie 返回给浏览器, 客户端(浏览器)这边就会通过 Cookie 保存当前用户的状态,当客户端访问服务器时,就会自动把 Cookie 内容带入到请求中,服务器接收到之后,就能知道当前客户是谁,现在客户端处于什么状态了,当前客户的服务提供到哪个环节了。Cookie 就像是 服务器在客户端搞的一个寄存处一样。
比如: 我们访问 抖音:
3. Cookie 的组成
-
Key(名称)
-
Value (值) : 根据 Key 可以获取对应的 value.
-
Domain(域名): 指定可以访问 Cookie 的域名。通常情况下,Cookie 只能被设置在创建它的域名以及其子域名下。上图中我们访问的是 抖音, 那么 Cookie 的 Domain 就是 douyin.com。
-
Path(路径): 指定可以访问 Cookie 的路径。这个字段定义了在哪些路径下的请求可以发送 Cookie。上图中 Path 为 “/”, 说明只要是 douyin.com 这个域名, 不管访问的是抖音 的哪个路径下的资源, 都可以在请求中使用浏览器中存储的 Cookie。
-
Expires(过期时间): 一旦过了这个时间,浏览器将不再发送该 Cookie。如果未设置 Expires 字段,Cookie 将被视为会话 Cookie,它会在用户关闭浏览器时自动删除。
-
大小: 指定了 Cookie 的大小,单位为字节。
-
HttpOnly: 布尔值字段,设置为 true,那么该 Cookie 只能通过 HTTP 或 HTTPS 协议访问,不能通过 JavaScript 或其他客户端脚本访问。有助于增强安全性,以防止恶意脚本访问敏感信息。
-
Secure: 布尔值字段,设置为 true,那么该 Cookie 只能在通过 HTTPS 等安全连接发送时才会被浏览器发送到服务器。有助于保护敏感信息的传输安全。
-
SameSite: 限制第三方cookie,表示Cookie不随着跨域请求发送,减少安全风险。它可以有三个可能的值:Strict、Lax、None。
Strict 表示只有在同一站点的请求中才会发送 Cookie;
Lax 在某些情况下允许 Cookie 在跨站点请求中发送(例如从外部链接打开的页面);
None 允许 Cookie 在任何情况下都发送。
SameSite 设置有助于减少跨站点请求伪造(CSRF)攻击和提高隐私。 -
Partition Key(分区键): 一个标识符,指示 Cookie 属于哪个上下文或分区。它通常用于在浏览器中隔离不同网站或应用程序的 Cookie 数据,以增强隐私和安全性。每个不同的域名下都可以有不同的 Cookie, 不同网站之间的 Cookie 并不冲突.
-
Priority(优先级): 指定了 Cookie 的传输优先级。Cookie数量超出限制时低优先级会被优先清除.
4. Cookie 的组织形式
- 先按照域名进行组织, 针对每个域名, 分别分配一块空间.
- 一块空间里又会按照键值对的方式组织数据.
5. Cookie 的传输
响应中: 服务器通过 Set-Cookie 字段返回 Cookie 给浏览器
此时 Cookie 中包含各个字段, 如 Domain, Path, HttpOnly 等, 这是服务器让浏览器知道什么时候才能使用这些 Cookie.
浏览器接收到 Cookie 后存储下来
再次发送请求时使用 Cookie 字段, 将 Cookie 发送给 服务器。
单看请求中的 Cookie 就是:
以键值对的形式, 只有 key 和 value, 没有其他字段, 其他字段只是辅助浏览器判断什么时候在请求中使用 Cookie 的.
服务器接收到包含 Cookie 的请求后,会解析 Cookie 并根据其中的信息执行相应的操作,例如,验证用户身份、提供个性化内容或记录用户活动等。
6. 如何提高 Cookie 的安全性
- 对 Cookie 中的信息加密.
- HttpOnly 设为 true, 那么该 Cookie 将只能通过 HTTP 或 HTTPS 协议访问,而不能通过 JavaScript 或其他客户端脚本访问, 防止其他恶意脚本访问 Cookie 盗取信息.
- Secure 设为 true, 只通过 HTTPS 等安全连接发送时才会被浏览器发送到服务器, 防止其他恶意网站窃取 Cookie 信息.
- 设置 Cookie 过期时间.
- 给 Cookie 设置 IP 戳和 时间 戳, 设置 Cookie 在同个 IP 下多长时间失效.
注意: 上面这些设置都是服务器设置的, 因为 Cookie 本身就是 服务器返回给浏览器, 浏览器只是简单的进行了存储.
7. Cookie 类
构造方法:
public Cookie(String name, String value) | name 表示 Cookie 的名称, value 就是对应的值 |
---|
普通方法:
方法名 | 说明 |
---|---|
String getName() | 该方法返回 cookie 的名称 |
String getValue() | 获取 cookie 的值 |
void setValue(String newValue) | 设置 cookie 的值 |
void setHttpOnly(boolean isHttpOnly) | 设置 HttpOnly 的值 |
void setSecure(boolean flag) | 设置 Secure 的值 |
void setDomain(String domain) | 设置可以访问 Cookie 的域名 |
… | … |
Cookie 有一系列对应的 get 和 set 方法.
通过 HttpServletResponse.addCookie() 可以向响应中添加新的 Cookie 键值对.
// 创建一个名为 "username" 的Cookie,并设置它的值为 "zhangsan"
Cookie cookie = new Cookie("username", "zhangsan");
// 设置Cookie的过期时间为1小时(以秒为单位)
cookie.setMaxAge(3600); // 3600秒 = 1小时
// 设置Cookie的路径,表示只有在指定路径下的请求才会发送该Cookie
cookie.setPath("/example");
// 设置Cookie的域名,表示只有在指定域名下的请求才会发送该Cookie
cookie.setDomain(".example.com");
// 设置Cookie为安全Cookie,只能在HTTPS连接下传输
cookie.setSecure(true);
// 设置HttpOnly属性,防止通过JavaScript访问Cookie
cookie.setHttpOnly(true);
// 将Cookie添加到HTTP响应中,以便将其发送到客户端
response.addCookie(cookie); // response 是 HttpServletResponse 的实例
通过 HttpServletRequest.getCookies() 获取到请求中的一系列 Cookie 键值对.
Cookie[] cookies = request.getCookies(); // request 是 HttpServletRequest 实例
Cookie 最重要的应用场景就是存储 会话 ID(SessionId), 进一步访问服务器后续页面时,能带上这个 id 从而让服务器知道当前用户信息。
二. Session
HTTP 协议自身是属于 “无状态” 协议.
“无状态” 的含义指的是:
- 默认情况下 HTTP 协议的客户端和服务器之间的这次通信, 和下次通信之间没有直接的联系.
但是实际开发中, 我们很多时候是需要知道请求之间的关联关系的.
例如登陆网站成功后, 第二次访问的时候服务器就能知道该请求是否是已经登陆过了。
上面的令牌通常就是服务器以 Cookie 形式返回给浏览器, 服务器存储的用户信息对应的就是 Session。通常情况下,一个用户关联一个 Session (会话)。
举个栗子: 这个过程和去医院看病很相似.
- 到了医院先挂号. 挂号时需提供身份证, 同时得到了一张 “就诊卡”, 这个就诊卡就相当于患者的 “令牌”. 同时医院的系统中会记录用户的看病信息。
- 后续去各个科室进行检查, 诊断, 开药等操作, 都不必再出示身份证了, 只要凭就诊卡即可识别出当前患者的身份,知道患者的病史。
- 看完病了之后, 不想要就诊卡了, 就可以注销这个卡. 此时患者的身份和就诊卡的关联就销毁了. (类似于网站的注销操作)
- 又来看病, 可以办一张新的就诊卡, 此时就得到了一个新的 “令牌”。
就诊卡就是 Cookie, 但是 Cookie 存储的数据是有限的,且易丢失,关键信息都存储在服务器上,以 会话(Session)的形式。
服务器这边就需要记录令牌信息, 以及令牌对应的用户信息, 这个就是 Session 机制所做的工作.
1. 理解会话机制 (Session)
-
服务器同一时刻收到的请求是很多的. 服务器需要清除的区分清楚每个请求是从属于哪个用户, 就需要在服务器这边记录每个用户令牌以及用户的信息的对应关系.
-
在上面的例子中, 就诊卡就是一张 “令牌”. 要想让这个令牌能够生效, 就需要医院这边通过系统记录每个就诊卡和患者信息之间的关联关系.
会话的本质就是一个 “哈希表”, 存储了一些键值对结构. key 就是令牌的 ID(token/sessionId), value 就是用户信息(用户信息可以根据需求灵活设计).
sessionId 是由服务器生成的一个 “唯一性字符串”, 又叫 token
- 当用户登陆的时候, 服务器在 Session 中新增一个新记录, 并把 sessionId / token 返回给客户端. (例如通过 HTTP 响应中的 Set-Cookie 字段返回).
- 客户端后续再给服务器发送请求的时候, 需要在请求中带上 sessionId/ token. (例如通过 HTTP 请求中的 Cookie 字段带上).
- 服务器收到请求之后, 根据请求中的 sessionId / token 在 Session 信息中获取到对应的用户信息, 再进行后续操作.
Servlet 的 Session 默认是保存在内存中的. 如果重启服务器则 Session 数据就会丢失,用户注销 Session 也会丢失, 同时 Session 也有过期时间。(Session 的默认过期时间30分钟)
2. Sessoin 的组织形式
HttpSession 这个对象本质也是一个 “键值对” 结构,每个 HttpSession 有其唯一的 ID,同时又包含若干键值对,里面的 key 和 value 由程序员自己定义,允许程序员往 HttpSession 对象中存储任意的键值对数据,但是 key 必须是 String , value 可以任意。
HttpSession 的每个键值对又称为属性(Attribute).
3. HttpSession 类
- 获取/创建 Session
HttpServletRequest 类 中有 获取 Session 的方法
方法 | 描述 |
---|---|
HttpSession getSession() | 在服务器中获取会话. 参数如果为 true, 则当不存在会话时新建会话; 参数如果为 false, 则当不存在会话时返回 null |
为什么根据 HttpServletRequest 类能获取到 Session ?
- 因为 HttpServletRequest 是对用户请求的抽象, 所以 HttpServletRequest 中会有请求中的 Cookie 信息,
- 其中非常重要的一个 Cookie 就是 sessionId, 根据这个 ID , 就能找到 (或者找不到)对应的 会话。
- 没找到时,说明之前没有创建,或者说过期了,
如果参数为 true, 就会创建会话,并在里面填写一些必要的信息并返回会话, 最终返回响应时,会将新建的 会话的 ID 通过 Set-Cookie 字段返回给浏览器。
如果为参数为 false, 直接返回 null.
响应中返回的 sessoinId
图中的 ZTZiMGRkY2YtYjQzYi00MWM3LTlhZjUtNTNkZmVkN2Q0MzM0 便是 sessionId
浏览器收到 Cookie 后, 进行存储,再次发送请求时便携带着这个 sessionId, 从而服务器能识别出来用户信息。
- HttpSession 类中的相关方法
一个 HttpSession 对象里面包含多个键值对. 我们可以往 HttpSession 中存任何我们需要的信息.
方法 | 描述 |
---|---|
Object getAttribute(String name) | 根据 name 获取 值,找不到返回 null. |
void setAttribute(String name, Object value) | 添加键值对, 键为 name , 值为 value |
boolean isNew() | 判定当前是否是新创建出的会话 |
创建会话并存入键值对:
// request 是 HttpServletRequest 实例
HttpSession session = request.getSession(true); // 参数为 true, 没有 session 就创建
// 存入键值对
session.setAttribute("username", "zhangsan");
session.setAttribute("age", 18);
session.setAttribute("password", "123456");
根据会话获取键值对:
// request 是 HttpServletRequest 实例
HttpSession session = request.getSession(false); // 参数为 false, 没有 session 返回 null, 通常用来验证用户是否已经登录时用
// 获取键值对, 注意要转换类型, 因为 返回值类型是 Object
String username = (String) session.getAttribute("username");
int age = (int) session.getAttribute("username");
String password = (String)session.getAttribute("password");
三. Cookie 和 Session 的联系与区别
联系:在网站的登录功能种,Cookie 与 Session 需要配合使用
区别:
- Cookie 是客户端的机制. Session 是服务器端的机制.
- Cookie 里面可以存储各种键值对(还可以存储别的),Session 专门用来保存用户的身份信息。
- Cookie 和 Session 经常会在一起配合使用. 但是不是必须配合.
完全可以用 Cookie 来保存一些数据在客户端. 这些数据不一定是用户身份信息, 也不一定是token / sessionId.
Session 中的 token / sessionId 也不需要非得通过 Cookie / Set-Cookie 传递.比如使用 手机 APP 进行登录,服务器里面还需要 Session, 但是就没有 Cookie 这个概念。也就是说 Cookie 是与 浏览器强相关的。
好啦! 以上就是对 Cookie 和 Session 的讲解,希望能帮到你 !
评论区欢迎指正 !