chrome 新的session 设置_为什么还是由这么多人搞不懂Cookie、Session、Token?

3dc9372b7efb305c9a947c6c949d3654.gif

作者:不学无数的程序员链接:https://urlify.cn/Yfm6Vr

# Cookie

 洛:大爷,楼上322住的是马冬梅家吧?  大爷:马都什么?  夏洛:马冬梅。  7大爷:什么都没啊?  夏洛:马冬梅啊。大爷:马什么没?夏洛:行,大爷你先凉快着吧。

在了解这三个概念之前我们先要了解HTTP是无状态的Web服务器,什么是无状态呢?就像上面夏洛特烦恼中经典的一幕对话一样,一次对话完成后下一次对话完全不知道上一次对话发生了什么。如果在Web服务器中只是用来管理静态文件还好说,对方是谁并不重要,把文件从磁盘中读取出来发出去即可。但是随着网络的不断发展,比如电商中的购物车只有记住了用户的身份才能够执行接下来的一系列动作。所以此时就需要我们无状态的服务器记住一些事情。

那么Web服务器是如何记住一些事情呢?既然Web服务器记不住东西,那么我们就在外部想办法记住,相当于服务器给每个客户端都贴上了一个小纸条。上面记录了服务器给我们返回的一些信息。然后服务器看到这张小纸条就知道我们是谁了。那么Cookie是谁产生的呢?Cookies是由服务器产生的。接下来我们描述一下Cookie产生的过程

  1. 浏览器第一次访问服务端时,服务器此时肯定不知道他的身份,所以创建一个独特的身份标识数据,格式为key=value,放入到Set-Cookie字段里,随着响应报文发给浏览器。

  2. 浏览器看到有Set-Cookie字段以后就知道这是服务器给的身份标识,于是就保存起来,下次请求时会自动将此key=value值放入到Cookie字段中发给服务端。

  3. 服务端收到请求报文后,发现Cookie字段中有值,就能根据此值识别用户的身份然后提供个性化的服务。

4acb4d58f77bcafe925bc6f144427f2c.png

接下来我们用代码演示一下服务器是如何生成,我们自己搭建一个后台服务器,这里我用的是SpringBoot搭建的,并且写入SpringMVC的代码如下。

@RequestMapping("/testCookies")public String cookies(HttpServletResponse response){    response.addCookie(new Cookie("testUser","xxxx"));    return "cookies";}

项目启动以后我们输入路径http://localhost:8005/testCookies,然后查看发的请求。可以看到下面那张图使我们首次访问服务器时发送的请求,可以看到服务器返回的响应中有Set-Cookie字段。而里面的key=value值正是我们服务器中设置的值。

f430d23dbafb1b5ac1cacd2adb3314ba.png

接下来我们再次刷新这个页面可以看到在请求体中已经设置了Cookie字段,并且将我们的值也带过去了。这样服务器就能够根据Cookie中的值记住我们的信息了。

82b223604a7e481d866475fd6a044a94.png

接下来我们换一个请求呢?是不是Cookie也会带过去呢?接下来我们输入路径http://localhost:8005请求。我们可以看到Cookie字段还是被带过去了。

66ff0258fc838f5cddf1947f11925be4.png

那么浏览器的Cookie是存放在哪呢?如果是使用的是Chrome浏览器的话,那么可以按照下面步骤。

  1. 在计算机打开Chrome

  2. 在右上角,一次点击更多图标->设置

  3. 在底部,点击高级

  4. 在隐私设置和安全性下方,点击网站设置

  5. 依次点击Cookie->查看所有Cookie和网站数据

然后可以根据域名进行搜索所管理的Cookie数据。所以是浏览器替你管理了Cookie的数据,如果此时你换成了Firefox等其他的浏览器,因为Cookie刚才是存储在Chrome里面的,所以服务器又蒙圈了,不知道你是谁,就会给Firefox再次贴上小纸条。

ce0ec76eb481bf1aadf4756d08293039.png

# Cookie中的参数设置

说到这里,应该知道了Cookie就是服务器委托浏览器存储在客户端里的一些数据,而这些数据通常都会记录用户的关键识别信息。所以Cookie需要用一些其他的手段用来保护,防止外泄或者窃取,这些手段就是Cookie的属性。

参数名作用后端设置方法
Max-Age设置cookie的过期时间,单位为秒cookie.setMaxAge(10)
Domain指定了Cookie所属的域名cookie.setDomain("")
Path指定了Cookie所属的路径cookie.setPath("");
HttpOnly告诉浏览器此Cookie只能靠浏览器Http协议传输,禁止其他方式访问cookie.setHttpOnly(true)
Secure告诉浏览器此Cookie只能在Https安全协议中传输,如果是Http则禁止传输cookie.setSecure(true)

下面我就简单演示一下这几个参数的用法及现象。

Path

设置为cookie.setPath("/testCookies"),接下来我们访问http://localhost:8005/testCookies,我们可以看到在左边和我们指定的路径是一样的,所以Cookie才在请求头中出现,接下来我们访问http://localhost:8005,我们发现没有Cookie字段了,这就是Path控制的路径。

c6318f81410701d01761e8b96c182127.png

Domain

设置为cookie.setDomain("localhost"),接下来我们访问http://localhost:8005/testCookies我们发现下图中左边的是有Cookie的字段的,但是我们访问http://172.16.42.81:8005/testCookies,看下图的右边可以看到没有Cookie的字段了。这就是Domain控制的域名发送Cookie。

9e9f992dbc6b43a17a423f9c121bea38.png

接下来的几个参数就不一一演示了,相信到这里大家应该对Cookie有一些了解了。

Session

Cookie是存储在客户端方,Session是存储在服务端方,客户端只存储SessionId

在上面我们了解了什么是Cookie,既然浏览器已经通过Cookie实现了有状态这一需求,那么为什么又来了一个Session呢?这里我们想象一下,如果将账户的一些信息都存入Cookie中的话,一旦信息被拦截,那么我们所有的账户信息都会丢失掉。所以就出现了Session,在一次会话中将重要信息保存在Session中,浏览器只记录SessionId一个SessionId对应一次会话请求。

3abbe79dd6b3e294c6d7b60583932dfc.png
 @RequestMapping("/testSession") @ResponseBody public String testSession(HttpSession session){     session.setAttribute("testSession","this is my session");     return "testSession"; }   @RequestMapping("/testGetSession")@ResponseBodypublic String testGetSession(HttpSession session){    Object testSession = session.getAttribute("testSession");    return String.valueOf(testSession);}

这里我们写一个新的方法来测试Session是如何产生的,我们在请求参数中加上HttpSession session,然后再浏览器中输入http://localhost:8005/testSession进行访问可以看到在服务器的返回头中在Cookie中生成了一个SessionId。然后浏览器记住此SessionId下次访问时可以带着此Id,然后就能根据此Id找到存储在服务端的信息了。

fe8dc1725bb7ac5cf16e10e7c4e101be.png

此时我们访问路径http://localhost:8005/testGetSession,发现得到了我们上面存储在Session中的信息。那么Session什么时候过期呢?

  • 客户端:和Cookie过期一致,如果没设置,默认是关了浏览器就没了,即再打开浏览器的时候初次请求头中是没有SessionId了。

  • 服务端:服务端的过期是真的过期,即服务器端的Session存储的数据结构多久不可用了,默认是30分钟。

bd7f20110dbd2103fcf25d6854b522de.png

既然我们知道了Session是在服务端进行管理的,那么或许你们看到这有几个疑问,Session是在在哪创建的?Session是存储在什么数据结构中?接下来带领大家一起看一下Session是如何被管理的。

Session的管理是在容器中被管理的,什么是容器呢?Tomcat、Jetty等都是容器。接下来我们拿最常用的Tomcat为例来看下Tomcat是如何管理Session的。在ManageBase的createSession是用来创建Session的。

 @Override public Session createSession(String sessionId) {     //首先判断Session数量是不是到了最大值,最大Session数可以通过参数设置     if ((maxActiveSessions >= 0) &&             (getActiveSessions() >= maxActiveSessions)) {         rejectedSessions++;         throw new TooManyActiveSessionsException(                 sm.getString("managerBase.createSession.ise"),                 maxActiveSessions);    }    // 重用或者创建一个新的Session对象,请注意在Tomcat中就是StandardSession    // 它是HttpSession的具体实现类,而HttpSession是Servlet规范中定义的接口    Session session = createEmptySession();    // 初始化新Session的值    session.setNew(true);    session.setValid(true);    session.setCreationTime(System.currentTimeMillis());    // 设置Session过期时间是30分钟    session.setMaxInactiveInterval(getContext().getSessionTimeout() * 60);    String id = sessionId;    if (id == null) {        id = generateSessionId();    }    session.setId(id);// 这里会将Session添加到ConcurrentHashMap中    sessionCounter++;    //将创建时间添加到LinkedList中,并且把最先添加的时间移除    //主要还是方便清理过期Session    SessionTiming timing = new SessionTiming(session.getCreationTime(), 0);    synchronized (sessionCreationTiming) {        sessionCreationTiming.add(timing);        sessionCreationTiming.poll();    }    return session}

到此我们明白了Session是如何创建出来的,创建出来后Session会被保存到一个ConcurrentHashMap中。可以看StandardSession类。

protected Map<String, Session> sessions = new ConcurrentHashMap<>();

到这里大家应该对Session有简单的了解了。

Session是存储在Tomcat的容器中,所以如果后端机器是多台的话,因此多个机器间是无法共享Session的,此时可以使用Spring提供的分布式Session的解决方案,是将Session放在了Redis中。

Token

Session是将要验证的信息存储在服务端,并以SessionId和数据进行对应,SessionId由客户端存储,在请求时将SessionId也带过去,因此实现了状态的对应。而Token是在服务端将用户信息经过Base64Url编码过后传给在客户端,每次用户请求的时候都会带上这一段信息,因此服务端拿到此信息进行解密后就知道此用户是谁了,这个方法叫做JWT(Json Web Token)。

dd4969c3b0156889cd4263ae2422f26a.png

Token相比较于Session的优点在于,当后端系统有多台时,由于是客户端访问时直接带着数据,因此无需做共享数据的操作。

# Token的优点

  1. 简洁:可以通过URL,POST参数或者是在HTTP头参数发送,因为数据量小,传输速度也很快

  2. 自包含:由于串包含了用户所需要的信息,避免了多次查询数据库

  3. 因为Token是以Json的形式保存在客户端的,所以JWT是跨语言的

  4. 不需要在服务端保存会话信息,特别适用于分布式微服务

# JWT的结构

实际的JWT大概长下面的这样,它是一个很长的字符串,中间用.分割成三部分

8db5701ea4c7c370ba6cb7c038328a70.png

JWT是有三部分组成的

Header

是一个Json对象,描述JWT的元数据,通常是下面这样子的

{  "alg": "HS256",  "typ": "JWT"}

上面代码中,alg属性表示签名的算法(algorithm),默认是 HMAC SHA256(写成 HS256);typ属性表示这个令牌(token)的类型(type),JWT 令牌统一写为JWT。最后,将上面的 JSON 对象使用 Base64URL 算法转成字符串。

JWT 作为一个令牌(token),有些场合可能会放到 URL(比如 api.example.com/?token=xxx)。Base64 有三个字符+、/和=,在 URL 里面有特殊含义,所以要被替换掉:=被省略、+替换成-,/替换成_ 。这就是 Base64URL 算法。

Payload

Payload部分也是一个Json对象,用来存放实际需要传输的数据,JWT官方规定了下面几个官方的字段供选用。

  • iss (issuer):签发人

  • exp (expiration time):过期时间

  • sub (subject):主题

  • aud (audience):受众

  • nbf (Not Before):生效时间

  • iat (Issued At):签发时间

  • jti (JWT ID):编号

当然除了官方提供的这几个字段我们也能够自己定义私有字段,下面就是一个例子

{  "name": "xiaoMing",  "age": 14}

默认情况下JWT是不加密的,任何人只要在网上进行Base64解码就可以读到信息,所以一般不要将秘密信息放在这个部分。这个Json对象也要用Base64URL算法转成字符串

Signature

Signature部分是对前面的两部分的数据进行签名,防止数据篡改。

首先需要定义一个秘钥,这个秘钥只有服务器才知道,不能泄露给用户,然后使用Header中指定的签名算法(默认情况是HMAC SHA256),算出签名以后将Header、Payload、Signature三部分拼成一个字符串,每个部分用.分割开来,就可以返给用户了。

HS256可以使用单个密钥为给定的数据样本创建签名。当消息与签名一起传输时,接收方可以使用相同的密钥来验证签名是否与消息匹配。

a5a73d77c0b6c4b300cc0ac16c679338.png

# Java中如何使用Token

上面我们介绍了关于JWT的一些概念,接下来如何使用呢?首先在项目中引入Jar包

compile('io.jsonwebtoken:jjwt:0.9.0')

然后编码如下

 // 签名算法 ,将对token进行签名 SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256; // 通过秘钥签名JWT byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary("SECRET"); Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName()); Map<String,Object> claimsMap = new HashMap<>(); claimsMap.put("name","xiaoMing"); claimsMap.put("age",14); JwtBuilder builderWithSercet = Jwts.builder()        .setSubject("subject")        .setIssuer("issuer")        .addClaims(claimsMap)        .signWith(signatureAlgorithm, signingKey);System.out.printf(builderWithSercet.compact());

发现输出的Token如下

eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJzdWJqZWN0IiwiaXNzIjoiaXNzdWVyIiwibmFtZSI6InhpYW9NaW5nIiwiYWdlIjoxNH0.3KOWQ-oYvBSzslW5vgB1D-JpCwS-HkWGyWdXCP5l3Ko

此时在网上随便找个Base64解码的网站就能将信息解码出来

b35089177a79dac07993e0df5eea6692.png

# 总结

相信大家看到这应该对Cookie、Session、Token有一定的了解了,接下来再回顾一下重要的知识点

  • Cookie是存储在客户端的

  • Session是存储在服务端的,可以理解为一个状态列表。拥有一个唯一会话标识SessionId。可以根据SessionId在服务端查询到存储的信息。

  • Session会引发一个问题,即后端多台机器时Session共享的问题,解决方案可以使用Spring提供的框架。

  • Token类似一个令牌,无状态的,服务端所需的信息被Base64编码后放到Token中,服务器可以直接解码出其中的数据。

 往期推荐 

?

  • SO面试题07:使用equlas和hashcode方法时,我们需要考虑那些问题?
  • TIOBE 3 月榜单:Delphi也许不属于这个时代了!!!
  • 别再说自己没时间,一文讲透操作系统

fcdc0ad4b6021d40d85a467b04ddfabc.png

585b190c57cabc1dc497068c9bb3dafc.gif 

点击

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

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

相关文章

mysql for update用处_for update的作用和用法

一、for update定义for update是一种行级锁&#xff0c;又叫排它锁&#xff0c;一旦用户对某个行施加了行级加锁&#xff0c;则该用户可以查询也可以更新被加锁的数据行&#xff0c;其它用户只能查询但不能更新被加锁的数据行&#xff0e;如果其它用户想更新该表中的数据行&…

python大数据零基础_零基础学习大数据人工智能,学习路线篇!

大数据处理技术怎么学习呢?首先我们要学习Python语言和Linux操作系统&#xff0c;这两个是学习大数据的基础&#xff0c;学习的顺序不分前后。Python&#xff1a;Python 的排名从去年开始就借助人工智能持续上升&#xff0c;现在它已经成为了语言排行第一名。从学习难易度来看…

python删除文件和linux删除文件区别_使用Python批量删除文件列表

使用Python批量删除文件列表环境&#xff1a;已知要删除的文件列表&#xff0c;即确定哪些文件要删除。代码如下&#xff1a;#!/usr/bin/env python#codingutf-8#目的&#xff1a;本程序主要为删除给定的文件列表import osimport shutil#引入模块&#xff0c;os为包含普遍的操作…

华为python有必要学吗_【华为云技术分享】这个 Python 库有必要好好学学

这里看一个最基本的例子&#xff0c;这里给到一个 User 的 Class 定义&#xff0c;再给到一个 data 数据&#xff0c;像这样&#xff1a;1 class User(object):2 def __init__(self, name, age):3 self.name name4 self.age age56 data [{7 name: Germey,8 age: 239 }, {10 nam…

python求平行四边形面积_python 已知平行四边形三个点,求第四个点的案例

我就废话不多说了&#xff0c;大家还是直接看代码吧&#xff01;import numpy as np#已知平行四边形三个点&#xff0c;求第四个点#计算两点之间的距离def CalcEuclideanDistance(point1,point2):vec1 np.array(point1)vec2 np.array(point2)distance np.linalg.norm(vec1 -…

eview面板数据之混合回归模型_【视频教程】Eviews系列25|面板数据回归分析之Hausman检验及本章常见问题解答...

点击上方关注我们!本期我们学习Eviews统计建模最后一部分--面板数据回归分析Hausman检验及本章常见问题解答。实操&#xff1a;Hausman检验判断是固定效应模型还是随机效应模型上期我们讲到模型判断若选择模型2,需进一步通过Hausman检验判断固定效应还是随机效应&#xff0c;接…

python打出由边框包围的_python opencv 图像边框(填充)添加及图像混合的实现方法(末尾实现类似幻灯片渐变的效果)...

图像边框的实现图像边框设计的主要函数cv.copyMakeBorder()——实现边框填充主要参数如下&#xff1a;参数一&#xff1a;源图像——如&#xff1a;读取的img参数二——参数五分别是&#xff1a;上下左右边的宽度——单位&#xff1a;像素参数六&#xff1a;边框类型&#xff1…

mysql5.7.21备份脚本_Shell脚本使用汇总整理——mysql数据库5.7.8以后备份脚本

#!/bin/sh#db_backups_conf.txt文件路径db_backups_conf"/wocloud/shell/db_backups_conf.txt"#判断文件是否存在if [ -f "${db_backups_conf}" ];thenecho $(date %Y-%m-%d %H:%M:%S)" 数据库配置信息文件存在&#xff0c;开始进行数据备份"#获…

python嵌套列表操作_python基础(list列表的操作,公共方法,列表嵌套,元祖)...

list 列表索引&#xff0c;切片与str相同。列表的操作(增删改查)1&#xff0c;增加.append()  追加&#xff0c;增加到最后li [alex,wusir,egon,女神,taibai]li.append(ppp)print(li).insert()  中间插入&#xff0c;通过索引li [alex,wusir,egon,女神,taibai]li.insert(…

mybatis mysql selectkey_Mybatis示例之SelectKey的应用

SelectKey在Mybatis中是为了解决Insert数据时不支持主键自动生成的问题&#xff0c;他可以很随意的设置生成主键的方式。不管SelectKey有多好&#xff0c;尽量不要遇到这种情况吧&#xff0c;毕竟很麻烦。SelectKey需要注意order属性&#xff0c;像Mysql一类支持自动增长类型的…

python程序设计上机实践第三章答案_20192419 实验三《Python程序设计》实验报告

学号 2019-2020-2 《Python程序设计》实验3报告课程&#xff1a;《Python程序设计》班级&#xff1a;1924姓名&#xff1a; 万腾阳学号&#xff1a;20192419实验教师&#xff1a;王志强实验日期&#xff1a;2020年5月16日必修/选修&#xff1a; 公选课1.实验内容创建服务端和客…

完成数独的算法 python_python实现数独算法实例

本文实例讲述了python实现数独算法的方法。分享给大家供大家参考。具体如下&#xff1a;# -*- coding: utf-8 -*-Created on 2012-10-5author: Administratorfrom collections import defaultdictimport itertoolsa [[ 0, 7, 0, 0, 0, 0, 0, 0, 0], #0[ 5, 0, 3, 0, 0, 6, 0, …

python读取多个文件csv_Python:读取多个文本文件并写入相应的csv文件

我在别处找不到这个问题的答案&#xff0c;所以我将继续把它贴在这里&#xff1a;我有一个Python脚本&#xff0c;它将读取文本文件的内容&#xff0c;将其内容拆分为单词&#xff0c;然后输出一个CSV文件&#xff0c;该文件将文本缩减为单词频率列表。(最后&#xff0c;我将插…

java treetable_在Swing中创建TreeTable | 学步园

TreeTable是Tree和Table的一个结合&#xff0d;就是一个即能够展开和收起行&#xff0c;同时也能够显示多个列的组件。在Swing的标准包里没有一个叫做JtreeTable的组件&#xff0c;但是我们很容易通过把Jtree做成Jtable的渲染器来创建一个这样的组件。这篇文章就是关于如何使用…

python爬去微博十大流行语_用python重新定义【2019十大网络流行语】-后台/架构/数据库-敏捷大拇指-一个敢保留真话的IT精英社区...

↑关注 置顶 ~ 有趣的不像个技术号52568040f9313098ffa367d9d9d21437.jpg (5.73 KB, 下载次数: 0)2019-12-10 04:43 上传3f4d5fe0016d011a7a68af763314befd.jpg (1.06 KB, 下载次数: 0)2019-12-10 04:43 上传“文明互鉴真硬核&#xff0c;融梗柠檬谁觉得。霸凌第一九九六&…

java中怎么获取配置文件的值_java如何获取配置文件的值

转&#xff1a;原创 编码小王子 发布于2018-10-11 18:07:52 阅读数 2722 收藏展开java大型项目中都会很多系统常量,比如说数据库的账号和密码,以及各种token值等,都需要统一的管理,如果零落的散布到各个类等具体的代码中的话,在后期管理上将是一场灾难,所有需要对这些变量进行统…

python实现队列_用Python实现的数据结构与算法:队列

一、概述队列(Queue)是一种先进先出(FIFO)的线性数据结构&#xff0c;插入操作在队尾(rear)进行&#xff0c;删除操作在队首(front)进行。二、ADT队列ADT(抽象数据类型)一般提供以下接口&#xff1a;Queue() 创建队列enqueue(item) 向队尾插入项dequeue() 返回队首的项&#xf…

java 监听窗口是否改变_JAVA项目监听文件是否发生变化

一.spring容器都初始化完成之后做操作packagecom.bijian.study.listener;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.context.ApplicationListener;importorg.springframework.context.event.ContextRefreshedEvent;importorg.s…

笨办法学python3 pdf 脚本之家_解决python3输入的坑——input()

如下所示&#xff1a;a,b,c,d input()很简单的代码&#xff0c;如果输入为1 -1 -2 3结果会报错&#xff0c;原因在于input函数会将你的输入作为python脚本运行&#xff0c;那么输入就变成了1-1 -2 3&#xff0c;即0 -2 3结果当然是错误的了&#xff0c;解决办法就是将输入用引…

java 数组写法_java书写、数据类型、数组定义

这里只记录java与php、javascript不同的地方&#xff0c;相同的地方就不赘述了。1.java文件源码为以.java为后缀的文件&#xff0c;字节码文件是以.class为后缀的文件。2.写好一个java源码之后&#xff0c;cmd进入源码文件盘符&#xff0c;用命令 javac helloworld.java将源码转…