学习笔记-Cookie、Session、JWT
目录
一、验证码的生成与校验
1. 创建生成验证码的工具类
2. 写一个 Controller
3. 实现验证码验证
1. 获取验证码
2. 验证码请求过程
3. 验证码的校验
4. 原理说明
5. 验证
6. 总结
二、JWT登录鉴权
1. 为什么要做登录鉴权?
2. 什么是 JWT
3. JWT相比传统的鉴权方式的优点
1. Session 认证
2. Session 认证的缺点
3. JWT 的优点
4. 创建 JWT
1. 引入依赖
2. 创建JWT 工具类
3. 生成一个token
5. 使用 JWT
1. Vue 导入依赖
2. 前端创建 Cookie 工具类
3. 在登录组件设置 token
4. 判断是否有 token
5. 发送 token
6. 服务器获取token
在登录页面加入图形验证码
一、验证码的生成与校验
1. 创建生成验证码的工具类
package com.Util;import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Random;public class ImageCodeUtils {/*** 图片的宽度*/private int width = 160;/*** 图片的高度*/private int height = 40;/*** 验证码字符个数*/private int codeCount = 4;/*** 验证码干扰线数*/private int lineCount = 20;/*** 验证码*/private String code = null;private BufferedImage buffImg = null;Random random = new Random();public ImageCodeUtils() {createImage();}public ImageCodeUtils(int width, int height) {this.width = width;this.height = height;createImage();}public ImageCodeUtils(int width, int height, int codeCount) {this.width = width;this.height = height;this.codeCount = codeCount;createImage();}public ImageCodeUtils(int width, int height, int codeCount, int lineCount) {this.width = width;this.height = height;this.codeCount = codeCount;this.lineCount = lineCount;createImage();}/*** 生成图片*/private void createImage() {// 字体的宽度int fontWidth = width / codeCount;// 字体的高度int fontHeight = height - 5;int codeY = height - 8;// 图像bufferbuffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);Graphics g = buffImg.getGraphics();// 设置背景色g.setColor(getRandColor(200, 250));g.fillRect(0, 0, width, height);// 设置字体//Font font1 = getFont(fontHeight);Font font = new Font("Fixedsys", Font.BOLD, fontHeight);g.setFont(font);// 设置干扰线for (int i = 0; i < lineCount; i++) {int xs = random.nextInt(width);int ys = random.nextInt(height);int xe = xs + random.nextInt(width);int ye = ys + random.nextInt(height);g.setColor(getRandColor(1, 255));g.drawLine(xs, ys, xe, ye);}// 添加噪点float yawpRate = 0.01f;int area = (int) (yawpRate * width * height);for (int i = 0; i < area; i++) {int x = random.nextInt(width);int y = random.nextInt(height);buffImg.setRGB(x, y, random.nextInt(255));}// 得到随机字符String str1 = randomStr(codeCount);this.code = str1;for (int i = 0; i < codeCount; i++) {String strRand = str1.substring(i, i + 1);g.setColor(getRandColor(1, 255));// a为要画出来的东西,x和y表示要画的东西最左侧字符的基线位于此图形上下文坐标系的 (x, y) 位置处g.drawString(strRand, i*fontWidth+3, codeY);}}/*** 得到随机字符串* @param n* @return*/private String randomStr(int n) {String str1 = "ABCDEFGHJKMNOPQRSTUVWXYZabcdefghjkmnopqrstuvwxyz1234567890";String str2 = "";int len = str1.length() - 1;double r;for (int i = 0; i < n; i++) {r = (Math.random()) * len;str2 = str2 + str1.charAt((int) r);}return str2;}/*** 得到随机颜色* @param fc* @param bc* @return*/private Color getRandColor(int fc, int bc) {if (fc > 255){fc = 255;}if (bc > 255){bc = 255;}int r = fc + random.nextInt(bc - fc);int g = fc + random.nextInt(bc - fc);int b = fc + random.nextInt(bc - fc);return new Color(r, g, b);}/*** 产生随机字体*/private Font getFont(int size) {Random random = new Random();Font[] font = new Font[5];font[0] = new Font("Ravie", Font.PLAIN, size);font[1] = new Font("Antique Olive Compact", Font.PLAIN, size);font[2] = new Font("Fixedsys", Font.PLAIN, size);font[3] = new Font("Wide Latin", Font.PLAIN, size);font[4] = new Font("Gill Sans Ultra Bold", Font.PLAIN, size);return font[random.nextInt(5)];}/*** 扭曲方法* @param g* @param w1* @param h1* @param color*/private void shear(Graphics g, int w1, int h1, Color color) {shearX(g, w1, h1, color);shearY(g, w1, h1, color);}private void shearX(Graphics g, int w1, int h1, Color color) {int period = random.nextInt(2);boolean borderGap = true;int frames = 1;int phase = random.nextInt(2);for (int i = 0; i < h1; i++) {double d = (double) (period >> 1)* Math.sin((double) i / (double) period+ (6.2831853071795862D * (double) phase)/ (double) frames);g.copyArea(0, i, w1, 1, (int) d, 0);if (borderGap) {g.setColor(color);g.drawLine((int) d, i, 0, i);g.drawLine((int) d + w1, i, w1, i);}}}private void shearY(Graphics g, int w1, int h1, Color color) {int period = random.nextInt(40) + 10;boolean borderGap = true;int frames = 20;int phase = 7;for (int i = 0; i < w1; i++) {double d = (double) (period >> 1)* Math.sin((double) i / (double) period+ (6.2831853071795862D * (double) phase)/ (double) frames);g.copyArea(i, 0, 1, h1, 0, (int) d);if (borderGap) {g.setColor(color);g.drawLine(i, (int) d, i, 0);g.drawLine(i, (int) d + h1, i, h1);}}}public void write(OutputStream sos) throws IOException {ImageIO.write(buffImg, "png", sos);sos.close();}public BufferedImage getBuffImg() {return buffImg;}public String getCode() {return code.toLowerCase();}
}
2. 写一个 Controller
方法:前端访问,调用一下工具类生成验证码图片并返回
引入一下依赖
<dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>4.0.1</version></dependency>
3. 实现验证码验证
1. 获取验证码
已经获取到验证码了,那么下一步怎么验证验证码呢?
2. 验证码请求过程
游览器那么多,服务器怎么知道是哪个游览器请求的?
这就可以使用到 Cookie 和 Session
3. 验证码的校验
把字符串形式的验证码存到 Session
从Session 中获取验证码
4. 原理说明
5. 验证
提示验证码错误
先查看验证验证码的SessionID是否和获取验证码的SessionID 一样
可以看到,两个是不同的SessionID ,服务器根据ID去获取的值是不同的,所以验证码错误
那么为什么是不同的呢?
这是因为 Vue 开启了代理转发,所以每次请求的 Cookie中JSESSIONID 值会发生变化
如何解决呢?
官方的解决方案是代理转发的 请求 URL 前缀和服务器请求路径的项目名相同就没问题了
原来的请求路径
修改后的请求路径
注意:vue 的配置文件修改后需要重启
修改服务器的 URL ,修改后重启服务器
可以看到SessionID值是一样的了
验证成功
6. 总结
- 会话开始:当一个用户首次访问一个网站,服务器会创建一个新的HttpSession对象,并生成一个唯一的会话ID(通常称为JSESSIONID)。
- 会话ID存储在Cookie中:服务器会在响应中包含一个Set-Cookie头,将这个会话ID作为cookie的一部分发送给浏览器。浏览器会存储这个cookie。
- 后续请求:当用户继续与网站交互时,浏览器会自动在每个后续请求中包含这个会话ID的cookie。这使得服务器能够识别出请求来自于哪个具体的会话。
- 服务器识别会话:服务器接收到请求后,会读取请求头中的cookie,提取出会话ID,然后使用这个ID在服务器端的会话存储中查找相应的HttpSession对象。
- 会话数据访问:一旦找到了HttpSession对象,服务器就可以从这个对象中读取或写入数据,比如用户信息、登录状态等。
- 会话结束:当用户关闭浏览器或会话超时,HttpSession对象会被销毁,除非服务器端有特别的配置来延长会话的存活时间。
二、JWT登录鉴权
JWT 全程 JSON Web Token
1. 为什么要做登录鉴权?
安全考虑,需要登录之后有操作权限了之后才能访问API接口
2. 什么是 JWT
JWT(JSON Web Token)是一种在网络应用中用于身份验证和授权的令牌。你可以把它想象成一张电子版的“身份证”或“通行证”。
当你登录一个网站后,服务器会生成一个JWT,JWT 本质就是一条字符串,它把你的身份信息(比如用户名)保存到一个JSON字符串中,然后进行编码得到一个token 令牌,然后把这个令牌发回给你的浏览器。之后,每当你的浏览器想要访问受保护的资源时,它都会带上这个JWT。
3. JWT相比传统的鉴权方式的优点
1. Session 认证
我们知道 HTTP 是一种无状态的协议,HTTP协议在设计上不保留任何两次请求之间的信息。换句话说,当你向一个网站发送请求时,比如浏览一个网页,这个请求是独立的,它并不依赖于你之前对该网站做的任何事情。一旦服务器处理完你的请求并返回了响应,它就会忘记这次交互,就像从来没有发生过一样。
所以为了让服务器知道是谁在访问,我们会在游览器第一次登陆成功的时候,创建一个SessionID,然后把用户信息保存在 Session 对象中,最后把SessionID放到 Cookie 返回给游览器,这样下次游览器再访问的时候就知道是谁了,这就是基于Session 认证的过程
2. Session 认证的缺点
由于基于Cookie,而cookie无法跨域,所以session的认证也无法跨域
Session 是保存在服务器的,会使服务器的开销增大
3. JWT 的优点
简洁,
无状态存储,以加密的形式保存在客户端,
时效性,可以设置多少时间失效
4. 创建 JWT
1. 引入依赖
<dependency><groupId>io.github.qyg2297248353.components</groupId><artifactId>jsonwebtoken-jjwt</artifactId><version>2.0.0</version></dependency>
2. 创建JWT 工具类
package com.Util;import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Map;
public class JwtUtil {// 私钥private static String privateKey = "12345678901234567890123456789012abcdefghijklmn";/** 生成token* @param claims 要加密的数据* @return* */public static String generateToken(Map<String, Object> claims) {// 使用JWT构建器构建令牌// 添加负载(claims),存储用户信息// 使用HS256算法和私钥进行签名,确保令牌的完整性和安全性// 最后将令牌以JSON格式编码,并压缩为紧凑字符串格式String token = Jwts.builder().addClaims(claims).signWith(SignatureAlgorithm.HS256, privateKey) // HS256加密,密钥长度必须大于等于256 bit.compact();return token;}
}
3. 生成一个token
在 Service 层调JWT工具类生成 token
登录成功后返回的 token
那么如何在每次请求都带上这个 token 呢?
可以把token 放到 Cookie 里
5. 使用 JWT
1. Vue 导入依赖
npm i js-cookie@2.2.0 -S
2. 前端创建 Cookie 工具类
3. 在登录组件设置 token
引入token 工具类的方法
4. 判断是否有 token
在路由器文件的路由守卫中判断,如果有 token 则放行
验证
5. 发送 token
在自定义 axios 文件的请求拦截器中添加 token 自定义 axios
可以看到在登录成功后,请求头里有 token
6. 服务器验证token
服务器在哪个 Controller 里判断?在所有 Controller 都判断一下比较麻烦
这就可以使用拦截器,在拦截器中统一判断
1. 创建登录拦截器
2. 配置拦截器
在spring 配置文件配置拦截器
<!--配置拦截器--><mvc:interceptors><mvc:interceptor><mvc:mapping path="/**"/> <!--拦截所有请求--><mvc:exclude-mapping path="/Admin/Login"/> <!--放行登录操作--><mvc:exclude-mapping path="/ImageCode/Captcha"/> <!--放行请求验证码--><bean class="com.Interceptor.LoginInterceptor"/></mvc:interceptor></mvc:interceptors>
这样就可以在每次请求资源时都带有token,服务器根据 token 判断是否有权限访问数据
目前,在 Vue 的路由守卫有判断是否登录(token)以及在服务器的拦截器也有判断
相关文章:

学习笔记-Cookie、Session、JWT
目录 一、验证码的生成与校验 1. 创建生成验证码的工具类 2. 写一个 Controller 3. 实现验证码验证 1. 获取验证码 2. 验证码请求过程 3. 验证码的校验 4. 原理说明 5. 验证 6. 总结 二、JWT登录鉴权 1. 为什么要做登录鉴权? 2. 什么是 JWT 3. JWT相比…...

题海战术,面试必胜秘诀
目录 1.Java 的优势是什么?2.什么是 Java 的多态特性?3.Java 中的参数传递是按值还是按引用?4.为什么 Java 不支持多重继承?5.什么是 Java 中的不可变类?总结 题目 来自面试鸭刷题神器 1.Java 的优势是什么? Java 的跨平台性、垃圾回收机制以及其强…...
设计模式详解(十九)——命令模式
命令模式简介 命令模式定义 命令模式(Command Pattern)是一种在面向对象程序设计中常用的行为型设计模式。命令模式的核心思想在于将请求封装成一个对象,从而使发出请求的责任和执行请求的责任分割开。它可以让请求发送者和请求接收者之间消…...

实战:MySQL数据同步神器之Canal
1.概叙 场景一:数据增量实时同步 项目中业务数据量比较大,每类业务表都达到千万级别,虽然做了分库分表,每张表数据控制在300W以下,但是效率还是达不到要求,为了提高查询效率,打算使用ES进行数…...
5.6软件工程-运维
运维 系统转换系统维护系统评价练习题 系统转换 新老系统的转换 系统转换是指:新系统开发完毕,投入运行,取代现有系统的过程,需要考虑多方面的问题,以实现与老系统的交接,有一下三种转换计划: …...
在JavaScript中如何确保构造函数只被new调用
构造函数是一个特殊的函数,用于初始化一个新创建的对象。它是在创建对象时自动调用的。构造函数通常用于为对象的属性赋值,或者执行其他必要的设置。 使用函数名大写字母开头,这是一种命名约定,用于区分构造函数和普通函数。如何…...

【数据结构算法经典题目刨析(c语言)】反转链表(图文详解)
💓 博客主页:C-SDN花园GGbond ⏩ 文章专栏:数据结构经典题目刨析(c语言) 目录 一、题目描述 二、思路分析 三、代码实现 一、题目描述: 二、思路分析 : 通过三个指针n1,n2,n3来实现链表的反转 1.首先初始化 n1为…...

机器学习之争:Python vs R,谁更胜一筹?
一、引言 随着人工智能和大数据的迅速发展,机器学习已成为现代科技的重要组成部分。在医疗、金融、零售、制造等多个领域,机器学习技术的应用无处不在。从数据分析到预测建模,再到深度学习,机器学习正在改变我们的工作和生活方式…...

Vulnhub靶机:JANGOW_ 1.0.1
目录 前言: 一、安装虚拟机Jangow:1.0.1靶机 二、Web部分 前言: 难度:简单,本文使用VirtualBox打开,下载地址: https://download.vulnhub.com/jangow/jangow-01-1.0.1.ova 一、安装虚拟机J…...
Python脚本实现USB自动复制文件
USB驱动器作为常见的数据存储设备,经常用于数据传输和备份。 然而,我们在手动处理文件复制可能效率低下且容易出错。 因此,我们可以利用Python编写脚本来自动化这一过程,提高效率和数据安全性。 准备工作 首先,我们需…...

【C++学习第19天】最小生成树(对应无向图)
一、最小生成树 二、代码 1、Prim算法 #include <cstring> #include <iostream> #include <algorithm>using namespace std;const int N 510, INF 0x3f3f3f3f;int n, m; int g[N][N]; int dist[N]; bool st[N];int prim() {memset(dist, 0x3f, sizeof di…...

第一个 Flask 项目
第一个 Flask 项目 安装环境创建项目启动程序访问项目参数说明Flask对象的初始化参数app.run()参数 应用程序配置参数使用 Flask 的 config.from_object() 方法使用 Flask 的 config.from_pyfile() 方法使用 Flask 的 config.from_envvar() 方法步骤 1: 设置环境变量步骤 2: 编…...

利用 Angular 发挥环境的力量
一.介绍 您是否曾想过如何在不同的环境中为同一应用设置不同的颜色、标题或 API 调用?可以肯定的是,生产 API 和测试 API 是不同的,应谨慎使用。部署时,我们不会在项目的所有地方手动更改所有 API 调用。不应这样做,因…...

Vue3+TypeScript+printjs 实现标签批量打印功能
前言:临时性需求没怎么接触过前端,代码实现有问题及优化点希望大佬可以留言告知一下 开发工具:VS CODE 界面开发:Vue3TypeScriptElementPlus 打印组件:Print-JS 前端打印入口图: 标签页面: …...

微信文件如何直接打印及打印功能在哪里设置?
在数字化时代,打印需求依旧不可或缺,但传统打印店的高昂价格和不便操作常常让人头疼。幸运的是,琢贝打印作为一款集便捷、经济、高效于一体的网上打印平台,正逐渐成为众多用户的首选。特别是通过微信小程序下单,更是让…...
dataX -20240804-master分支
1、相关报错 Error: java.io.IOException: java.lang.RuntimeException: ORC split generation failed with exception: org.apache.orc.impl.SchemaEvolution$IllegalEvolutionException: ORC does not support type conversion from file type struct<nanos:int> (10)…...

【网络】传输层
传输层 一、预备知识1、端口号1、端口号范围划分2、知名端口号3、两个问题4、netstat && iostate5、pidof6、谈下面协议始终铭记两个问题 二、UDP协议(简单)1、UDP协议端格式2、UDP的特点3、面向数据报4、UDP缓冲区 三、TCP协议(重点…...

学生管理系统之更新和删除、筛选
学生管理系统之更新和删除 建立新的窗口 添加组件 进行布局 使用Widget把二个放在一块,作为一列,然后全选进行栅格布局,最后添加弹簧进行微调。 编写增加的槽函数 在主函数中调用对话框...

教您一键批量下载拼多多批发图片信息,节省时间
图片是电商的核心展示手段,高质量、吸引人的图片能显著提升商品吸引力,增强用户体验,促进购买决策。良好的视觉呈现有助于品牌形象的塑造,提高转化率和客户满意度,对电商平台的流量和销售业绩具有直接影响。 使用图快…...

基于微信小程序的微课堂笔记的设计与实现(源码+论文+部署讲解等)
博主介绍:✌全网粉丝10W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌ 技术栈介绍:我是程序员阿龙ÿ…...
生成xcframework
打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式,可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...

7.4.分块查找
一.分块查找的算法思想: 1.实例: 以上述图片的顺序表为例, 该顺序表的数据元素从整体来看是乱序的,但如果把这些数据元素分成一块一块的小区间, 第一个区间[0,1]索引上的数据元素都是小于等于10的, 第二…...

label-studio的使用教程(导入本地路径)
文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

循环冗余码校验CRC码 算法步骤+详细实例计算
通信过程:(白话解释) 我们将原始待发送的消息称为 M M M,依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)(意思就是 G ( x ) G(x) G(x) 是已知的)࿰…...

python/java环境配置
环境变量放一起 python: 1.首先下载Python Python下载地址:Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个,然后自定义,全选 可以把前4个选上 3.环境配置 1)搜高级系统设置 2…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序
一、开发环境准备 工具安装: 下载安装DevEco Studio 4.0(支持HarmonyOS 5)配置HarmonyOS SDK 5.0确保Node.js版本≥14 项目初始化: ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...

Ascend NPU上适配Step-Audio模型
1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统,支持多语言对话(如 中文,英文,日语),语音情感(如 开心,悲伤)&#x…...

Mac下Android Studio扫描根目录卡死问题记录
环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题
在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件,这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下,实现高效测试与快速迭代?这一命题正考验着…...