【面试题】深入理解Cookie、Session、Token的区别

news2025/1/15 13:11:00

【面试题】深入理解Cookie、Session、Token的区别

Cookie与Session

Session

Cookie与Session之前的联系

Cookie与Session的在请求中的工作流程

Cookie与Session存在问题

Token

什么是Token? 

为什么要有token?

token认证机制 

Token流程 

cookie、sessionStorage、localStorage的区别

代码实现

登入功能 

登入拦截器  

Redis的token自动刷新拦截器


【面试题】深入理解Cookie、Session、Token的区别

Cookie与Session

Cookie,它是客户端浏览器用来保存服务端数据的一种机制。

当通过浏览器进行网页访问的时候,服务器可以把某一些状态数据key-value的方式写入到 Cookie 里面存储到客户端浏览器

然后客户端下一次再访问服务器的时候,就可以携带这些状态数据发送到服务器端,服务端可以根据 Cookie 里面携带的内容识别使用者

Session

Session 表示一个会话,它是属于服务器端的容器对象。

默认情况下,针对每一个浏览器的请求,Servlet 容器都会分配一个 Session。

Session 本质上是一个 ConcurrentHashMap,可以存储当前会话产生的一些状态数据。

Cookie与Session之前的联系

我们都知道,Http 协议本身是一个无状态协议,也就是服务器并不知道客户端发送过来的多次请求是属于同一个用户

所以 Session 是用来弥补 Http 无状态的不足,简单来说,服务器端可以利用session 来存储客户端在同一个会话里面的多次请求记录。

基于服务端的 session 存储机制,再结合客户端的 Cookie 机制,就可以实现有状态的 Http 协议。 

cookie存储是有效期,可以自行通过expires进行具体的日期设置;如果没设置,默认是关闭浏览器时失效

当客户端存储的cookie失效后,服务端的session不会立即销毁,会有一个延时,服务端会定期清理无效session,不会造成无效数据占用存储空间的问题。

Cookie与Session的在请求中的工作流程

(1)客户端第一次访问服务端的时候,服务端会针对这次请求创建一个会话,并生成一个唯一的 sessionID 来标注这个会话。

(2)然后服务端把这个 sessionID 写入到客户端浏览器的 cookie 里面,用来实现客户端状态的保存。

(3)在后续的请求里面,每次都会携带sessionID,服务器端就可以根据这个sessionID 来识别当前的会话状态。 

所以,总的来说,Cookie 客户端的存储机制,Session 服务端的存储机制。

Cookie与Session存在问题

当项目的并发量越来越大的时候,我们一台服务器不够,想要有多台Tomcat来部署一个Tomcat集群时,由于Session是不能共享的,所以该场景不适用!

如果是前后端分离的项目,即前端代码和后端代码部署在不同的服务器上时,也是不可以使用Session进行登入的! 

Token

什么是Token? 

token的意思是“令牌”,是服务端生成的一串字符串,作为客户端进行请求的一个标识。

当用户第一次登录后,服务器生成一个token,并将此token返回给客户端,以后客户端只需带上这个token前来请求数据即可,无需再次带上用户名和密码。

为什么要有token?

  1. Token 可以是无状态的,可以在多个服务间共享

  2. Token 可以避免 CSRF攻击(跨站点请求伪造)
  3. 减轻服务器压力。通常session是存储在内存中的,每个用户通过认证之后都会将session数据保存在服务器的内存中,而当用户量增大时,服务器的压力增大。

token认证机制 

Token流程 

  1. 客户端使用用户名和密码请求登录。
  2. 服务端收到请求,验证用户名和密码。
  3. 验证成功后,服务端会生成一个token(存在redis中),然后把这个token发送给客户端。
  4. 客户端收到token后把它存储起来,可以放在cookie或者Local Storage(本地存储)里。
  5. 客户端每次向服务端发送请求的时候都需要带上服务端发给的token。
  6. 服务端收到请求,然后去验证客户端请求里面带着token,如果验证成功,就向客户端返回请求的数据。(如果这个 Token 在服务端持久化(比如存入数据库),那它就是一个永久的身份令牌。)

请求登录时,token和sessionId原理相同,是对key和key对应的用户信息进行加密后的加密字符,登录成功后,会在响应主体中将{token:'字符串'}返回给客户端。

客户端通过cookie、sessionStorage、localStorage都可以进行存储。再次请求时不会默认携带,需要在请求拦截器位置给请求头中添加认证字段Authorization携带token信息,服务器端就可以通过token信息查找用户登录状态。

cookie、sessionStorage、localStorage的区别

  • cookie、sessionStorage、localStorage 都是用于本地存储的技术。其中 cookie 出现最早,但是存储容量较小,仅有4KB;sessionStoragelocalStorage存储容量要比cookie大很多,为5MB。

  • 接下来对 sessionStorage、localstorage 进行比较。其中sessionStorage 的数据存储局限于浏览器窗口,只适合于单页面应用程序使用,因为sessionStorage打开浏览器新标签,会话状态不会共享;而localstorage 的数据存储位于本地文件夹中,用户关闭浏览器后再次打开时,数据仍会存在。

代码实现

登入功能 

第一次登入的时候,会走下面的逻辑,生成一个随机、唯一的token。将<token,user> 存入redis

之后,如果在这个redis的key的TTL内,再次登入,就不需要走这个逻辑了!会走下面的拦截器的逻辑! 

@Override
public Result login(LoginFormDTO loginForm, HttpSession session) {

    //1. 校验手机号
    String phone = loginForm.getPhone();
    if (RegexUtils.isPhoneInvalid(phone)) {
        return Result.fail("手机号格式错误");
    }

    //2. 从redis获取验证码并校验
    String cacheCode = stringRedisTemplate.opsForValue().get(LOGIN_CODE_KEY + phone);
    String code = loginForm.getCode();
    if (cacheCode == null || !cacheCode.toString().equals(code)){
        //3. 不一致,报错
        return Result.fail("验证码错误");
    }

    //4.一致,根据手机号查询用户
    User user = query().eq("phone", phone).one();

    //5. 判断用户是否存在
    if (user == null){
        //6. 不存在,创建新用户
        user = createUserWithPhone(phone);
    }

    //7.保存用户信息到redis
    //7.1 生成随机token作为登入令牌
    String token = UUID.randomUUID().toString(true);

    //7.2 将User对象作为HashMap存储
    UserDTO userDTO = BeanUtil.copyProperties(user, UserDTO.class);
    // 注意!!!
    Map<String, Object> userMap = BeanUtil.beanToMap(userDTO,new HashMap<>(),
            CopyOptions.create().setIgnoreNullValue(true).setFieldValueEditor((fileName,fileValue) -> fileValue.toString()));

    //7.3 存储
    String tokenKey = LOGIN_USER_KEY + token;
    stringRedisTemplate.opsForHash().putAll(tokenKey,userMap);

    //7.4设置token的有效期
    stringRedisTemplate.expire(tokenKey,LOGIN_USER_TTL,TimeUnit.MINUTES);

    //8.返回token
    return Result.ok(token);
}

登入拦截器  

@Component
public class LoginInterceptor implements HandlerInterceptor {

    // 基于Redis设置的拦截器
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        //判断是否要拦截
        if (UserHolder.getUser() == null) {
            response.setStatus(401);
            return false;
        }

        //有用户,放行
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //移除用户
        UserHolder.removeUser();
    }
}

Redis的token自动刷新拦截器

从HTTP请求头中获取 authorization (因为这里的前端将用户的token放在了这里面)!

拦截器中,用刚刚解析出来的token,去查redis,判断是否有该用户(是否在登入有效期内)

用户每次操作都会自动刷新(推迟) Token 的过期时间 

@Component
public class RefreshTokenInterceptor implements HandlerInterceptor {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 1.获取请求头中的token
        String token = request.getHeader("authorization");
        if (StrUtil.isBlank(token)) {
            return true;
        }
        // 2.基于TOKEN获取redis中的用户
        String key = LOGIN_USER_KEY + token;
        Map<Object, Object> userMap = stringRedisTemplate.opsForHash().entries(key);
        // 3.判断用户是否存在
        if (userMap.isEmpty()) {
            return true;
        }
        // 5.将查询到的hash数据转为UserDTO
        UserDTO userDTO = BeanUtil.fillBeanWithMap(userMap, new UserDTO(), false);
        // 6.存在,保存用户信息到 ThreadLocal
        UserHolder.saveUser(userDTO);
        // 7.刷新token有效期
        stringRedisTemplate.expire(key, LOGIN_USER_TTL, TimeUnit.MINUTES);
        // 8.放行
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 移除用户
        UserHolder.removeUser();
    }
}

将上述两个拦截器,加到 MvcConfig 里面

@Configuration
public class MvcConfig implements WebMvcConfigurer {

    @Autowired
    private LoginInterceptor loginInterceptor;

    @Autowired
    private RefreshTokenInterceptor refreshTokenInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 登录拦截器
        registry.addInterceptor(loginInterceptor)
                .excludePathPatterns(
                        "/shop/**",
                        "/voucher/**",
                        "/shop-type/**",
                        "/upload/**",
                        "/blog/hot",
                        "/user/code",
                        "/user/login"
                ).order(1);

        // token刷新的拦截器
        registry.addInterceptor(refreshTokenInterceptor)
                .addPathPatterns("/**").order(0);
    }
}

 

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

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

相关文章

灵界的科学丨五、心灵与意识的科学奥祕

摘自李嗣涔教授《灵界的科学》 每个人都有「自我意识」&#xff0c; 每天睡觉时「我」就不见了&#xff0c; 每天早上醒来时&#xff0c;「我」又回来了&#xff0c; 好像没有太大的改变&#xff0c; 这个「我」的物理现象是什么&#xff1f; 探索科学的最后疆界──意识 …

【感恩系列】:说点事儿 以及 我把所有的粉丝放到了中国地图上啦~

文章目录&#x1f49e;许久不见&#xff0c;甚是想念&#x1f498;初次相遇&#x1f498;为什么写博客&#xff1f;&#x1f498;写博客的收获&#x1f498;此可已无言&#x1f498;中国版图里的我们&#x1f496;设计思路&#xff1a;&#x1f496;具体实现&#x1f495;爬取粉…

【毕业设计】56-辅助驾驶系统的视觉检测\超声波\图像识别\装置研究与设计(原理图工程、仿真工程、低重复率设计文档、答辩PPT、开题报告)

【毕业设计】56-辅助驾驶系统的视觉检测\超声波\图像识别\装置研究与设计&#xff08;原理图工程、仿真工程、低重复率设计文档、答辩PPT、开题报告&#xff09; 文章目录【毕业设计】56-辅助驾驶系统的视觉检测\超声波\图像识别\装置研究与设计&#xff08;原理图工程、仿真工…

HCIP实验2-1:IS-IS 配置实验

实验 2-1 IS-IS 配置实验 实验目标 掌握IS-IS协议基本配置掌握IS-IS协议DIS优先级修改方式掌握IS-IS协议网络类型修改方式掌握IS-IS协议外部路由引入掌握IS-IS接口cost修改方式掌握IS-IS路由渗透配置方式 拓扑图 场景 使用IS-IS协议作为某网络的IGP&#xff0c;R1和R5运行在…

操作系统:操作系统概论

目录前言1. 操作系统概观1.1 操作系统与计算机系统1.1.1 操作系统1.1.2 硬件软件1.1.2.1 硬件1.1.2.2 软件1.1.2.2.1 系统软件&#xff08;操作系统层&#xff09;1.1.2.2.2 支撑软件1.1.2.2.3 应用软件1.2 操作系统资源管理技术1.2.1 资源管理1.2.1.1 资源复用1.2.1.2 资源虚化…

线性代数---第五章特征值和特征向量

1特征值的和等于a11加上a22&#xff0c;特征值的积等于行列式 2利用|λE-A|0求特征值&#xff0c;代入特征值求基础解系&#xff0c;利用基础解系求特征向量 3如果两个特征值相等&#xff0c;那么它们的特征向量也相等 当特征值是二重根时&#xff0c;有可能有一个线性无关的特…

EndNote安装与使用

一、安装 1、双击ENX9Inst.msi安装 2、进入安装目录&#xff0c;使用CHS或ENG里的文件替换安装目录文件 CHS 中文版 ENG 英文版 二、软件优化 1、EndNote Import.enf 此文件用于导入中文文献时期刊名解析错误的问题&#xff0c;右击使用EndNoteX9打开后关闭即可 2、geebin…

Navicat导入SQL文件

安装Navicat 软件下载地址 https://wwz.lanzoub.com/i3T9S0gbq2wd 参考链接接 https://www.cnblogs.com/hhaostudy/p/15898030.html 准备导入SQL文件 新建连接 点击左上角连接 -> 选择MySQL 连接名&#xff1a;任意名称都可以&#xff0c;可输入localhost 主机&#x…

[计算机毕业设计]网络流量的在线恶意应用检测系统

前言 &#x1f4c5;大四是整个大学期间最忙碌的时光,一边要忙着准备考研,考公,考教资或者实习为毕业后面临的就业升学做准备,一边要为毕业设计耗费大量精力。近几年各个学校要求的毕设项目越来越难,有不少课题是研究生级别难度的,对本科同学来说是充满挑战。为帮助大家顺利通过…

【Pytorch with fastai】第 17 章 :基础神经网络

&#x1f50e;大家好&#xff0c;我是Sonhhxg_柒&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流&#x1f50e; &#x1f4dd;个人主页&#xff0d;Sonhhxg_柒的博客_CSDN博客 &#x1f4c3; &#x1f381;欢迎各位→点赞…

【LeetCode每日一题:799.香槟塔~~~模拟】

题目描述 我们把玻璃杯摆成金字塔的形状&#xff0c;其中 第一层 有 1 个玻璃杯&#xff0c; 第二层 有 2 个&#xff0c;依次类推到第 100 层&#xff0c;每个玻璃杯 (250ml) 将盛有香槟。 从顶层的第一个玻璃杯开始倾倒一些香槟&#xff0c;当顶层的杯子满了&#xff0c;任…

〖全域运营实战白宝书 - 运营角色认知篇①〗- 初识运营,明晰运营的学习路径

✌ 大家好&#xff0c;我是 哈士奇 &#xff0c;一位工作了十年的"技术圈混子"&#xff0c; 致力于为开发者赋能的UP主, 目前正在运营着 TFS_CLUB社区。 ✌ &#x1f4ac; 人生格言&#xff1a;优于别人,并不高贵,真正的高贵应该是优于过去的自己。&#x1f4ac; &am…

ES6 入门教程 14 Set 和 Map 数据结构 14.1 Set

ES6 入门教程 ECMAScript 6 入门 作者&#xff1a;阮一峰 本文仅用于学习记录&#xff0c;不存在任何商业用途&#xff0c;如侵删 文章目录ES6 入门教程14 Set 和 Map 数据结构14.1 Set14.1.1 基本用法14.1.2 Set 实例的属性和方法14.1.3 遍历操作14 Set 和 Map 数据结构 14.1…

[附源码]java毕业设计实验教学过程管理平台

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

【龙芯1B】:74HC595数码管或74HC138数码管程序开发

学习目标&#xff1a;解决龙芯1B&#xff1a;74HC595或74HC138数码管显示问题 首先我们要知道数码管的原理&#xff1b;以74HC595为例&#xff0c;74HC595是具有三态输出功能&#xff08;即具有高电平、低电平和高阻抗三种输出状态&#xff09;的门电路。输出寄存器可以直接清除…

基于Springboot搭建java项目(十六)——Kafka的简介

kafka官网&#xff1a;http://kafka.apache.org/ 参考文献&#xff1a;大白话 kafka 架构原理 (qq.com) 一、kafka简介 Kafka最初由Linkedin公司开发&#xff0c;是一个分布式的、分区的、多副本的、多订阅者&#xff0c;基于zookeeper协调的分布式日志系统&#xff08;也可…

[附源码]计算机毕业设计JAVA后疫情下物业管理系统

[附源码]计算机毕业设计JAVA后疫情下物业管理系统 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM my…

数据传输功能单元——DID参数定义

诊断协议那些事儿 诊断协议那些事儿专栏系列文章&#xff0c;本文介绍数据传输服务的dataldentifier&#xff08;DID&#xff09;定义。 参考文章&#xff1a; 22服务-ReadDataByIdentifier 文章目录诊断协议那些事儿一、DID参数二、参数的定义总结一、DID参数 逻辑上&#…

MongoDB初识(一)

什么是MongoDB MongoDB 是一个以JSON为数据模型的文档数据库&#xff0c;文档来自于“JSON Document”&#xff0c;并非我们一般理解的PDF&#xff0c;WORD文档 MongoDB中的记录就是一个文档&#xff0c;它是由键值对组成的数据结构。MongoDB 文档类似于 JSON 对象。字段的值…

基于农产品(蔬菜)数据挖掘的分析与实现(Python+Spider)

目 录 摘 要 I Abstract II 1绪论 1 1.1研究背景 1 1.2项目来源 1 1.3研究目的 2 1.3研究现状 2 1.4主要内容及预期目标 3 1.4.1数据挖掘技术简述及优点 3 1.4.2程序设计思路 3 1.4.3节点布置方案 4 1.4.4预期目标 5 2农产品&#xff08;蔬菜&#xff09;价格形成机制及影响因素…