七天免登录 为什么不能用seesion,客户端的http请求自动携带cookei的机制(比较重要)涉及HTTP规范
如果是七天免登录,和session肯定没关系,因为session不能持久化,主要是客户端一旦关闭,seesion就失效了///
所以必须是能持久化的,这就清晰了,要莫在的服务器保存,要摸在客户端设置
cook机制
1. 使用Cookie实现七天免登录
前端(登录页面)
在登录页面中,提供一个“记住我”选项,允许用户选择是否启用免登录功能。
jsp复制
<form action="LoginServlet" method="post"><input type="text" name="account" placeholder="请输入账号"><input type="password" name="password" placeholder="请输入密码"><input type="checkbox" name="remember" value="1">记住我<input type="submit" value="登录">
</form>
后端(Servlet)
在登录成功后,根据用户是否勾选“记住我”,设置一个有效期为7天的Cookie。
java复制
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String account = req.getParameter("account");String password = req.getParameter("password");String remember = req.getParameter("remember");// 模拟用户验证boolean isValidUser = "admin".equals(account) && "123".equals(password);if (isValidUser) {// 如果用户勾选了“记住我”if ("1".equals(remember)) {Cookie cookie = new Cookie("auth_token", URLEncoder.encode(account + "-" + password, "utf-8"));cookie.setMaxAge(7 * 24 * 60 * 60); // 设置Cookie有效期为7天cookie.setPath("/"); // 设置Cookie路径resp.addCookie(cookie);}// 跳转到主页resp.sendRedirect("index.jsp");} else {// 跳转回登录页面resp.sendRedirect("login.jsp?error=true");}
}
自动登录逻辑
在用户访问主页时,检查Cookie是否存在并有效。
java复制
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {Cookie[] cookies = req.getCookies();if (cookies != null) {for (Cookie cookie : cookies) {if ("auth_token".equals(cookie.getName())) {String[] userInfo = URLDecoder.decode(cookie.getValue(), "utf-8").split("-");String account = userInfo[0];String password = userInfo[1];// 模拟验证用户信息if ("admin".equals(account) && "123".equals(password)) {// 自动登录成功,跳转到主页resp.sendRedirect("index.jsp");return;}}}}// 如果没有找到有效的Cookie,跳转到登录页面resp.sendRedirect("login.jsp");
}
2. 使用JWT实现七天免登录
后端(生成JWT)
在用户登录成功后,生成一个有效期为7天的JWT,并将其存储在Cookie中。
java复制
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;import java.util.Date;public class JwtUtil {private static final String SECRET_KEY = "your_jwt_secret_key";public static String generateToken(String subject) {long nowMillis = System.currentTimeMillis();Date now = new Date(nowMillis);long expMillis = nowMillis + 7L * 24 * 60 * 60 * 1000; // 7天有效期Date exp = new Date(expMillis);return Jwts.builder().setSubject(subject).setIssuedAt(now).setExpiration(exp).signWith(SignatureAlgorithm.HS256, SECRET_KEY).compact();}
}
在登录成功后,将JWT存储在Cookie中。
java复制
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String account = req.getParameter("account");String password = req.getParameter("password");// 模拟用户验证boolean isValidUser = "admin".equals(account) && "123".equals(password);if (isValidUser) {String token = JwtUtil.generateToken(account);Cookie cookie = new Cookie("auth_token", token);cookie.setMaxAge(7 * 24 * 60 * 60); // 设置Cookie有效期为7天cookie.setPath("/");resp.addCookie(cookie);resp.sendRedirect("index.jsp");} else {resp.sendRedirect("login.jsp?error=true");}
}
验证JWT
在每次请求时,验证JWT的有效性。
java复制
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;public class JwtUtil {private static final String SECRET_KEY = "your_jwt_secret_key";public static Claims parseToken(String token) {return Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody();}
}
在过滤器中验证JWT。
java复制
@Override
protected void doFilterInternal(HttpServletRequest req, HttpServletResponse resp, FilterChain filterChain) throws ServletException, IOException {Cookie[] cookies = req.getCookies();if (cookies != null) {for (Cookie cookie : cookies) {if ("auth_token".equals(cookie.getName())) {try {Claims claims = JwtUtil.parseToken(cookie.getValue());// 如果JWT有效,继续处理请求filterChain.doFilter(req, resp);return;} catch (Exception e) {// JWT无效,跳转到登录页面resp.sendRedirect("login.jsp");return;}}}}// 如果没有找到有效的JWT,跳转到登录页面resp.sendRedirect("login.jsp");
}
注意事项
-
安全性:为了确保安全性,建议使用HTTPS协议传输数据,避免Cookie或JWT被窃取。
-
Cookie设置:如果使用Cookie存储JWT,建议设置
httpOnly属性,防止JavaScript访问Cookie,从而降低XSS攻击的风险。 -
定期更新:定期更新JWT或Cookie的密钥,防止被恶意攻击者破解。
HTTP请求会携带Cookie的原因主要与Cookie的设计初衷和工作原理有关。Cookie是一种存储在客户端(通常是浏览器)的轻量级数据存储机制,用于在用户与服务器之间保持会话状态。以下是详细解释:
1. Cookie的设计初衷
-
保持会话状态:HTTP协议本身是无状态的,这意味着服务器不会自动记住用户之前的请求。每次HTTP请求都是独立的,服务器无法区分是同一个用户还是不同用户发起的请求。为了弥补这一缺陷,Cookie被设计出来,用于在客户端存储少量数据,以便在后续请求中携带这些数据,从而让服务器能够识别用户的身份或状态。
-
个性化体验:通过Cookie,网站可以记住用户的偏好设置(如语言、主题、登录状态等),从而为用户提供个性化的体验。
2. Cookie的工作原理
-
服务器设置Cookie:当用户第一次访问网站时,服务器可能会在响应中包含一个
Set-Cookie头,告诉浏览器存储一些数据。例如:http复制
Set-Cookie: session_id=1234567890; Path=/; HttpOnly这里,服务器告诉浏览器存储一个名为
session_id的Cookie,值为1234567890,并且该Cookie适用于网站的所有路径(Path=/)。 -
浏览器存储Cookie:浏览器接收到
Set-Cookie头后,会将这些Cookie存储在本地。存储的位置和方式因浏览器而异,但通常会以键值对的形式保存。 -
浏览器自动携带Cookie:在后续的HTTP请求中,浏览器会自动将与当前请求相关的Cookie附加到请求的
Cookie头中。例如:http复制
GET / HTTP/1.1 Host: example.com Cookie: session_id=1234567890浏览器会根据Cookie的
Path、Domain等属性,判断哪些Cookie应该附加到当前请求中。
3. 为什么HTTP请求会自动携带Cookie?
-
浏览器的自动管理机制:浏览器会自动管理Cookie的存储和发送。当浏览器发起HTTP请求时,它会检查本地存储的Cookie,找出与当前请求匹配的Cookie,并将它们附加到请求的
Cookie头中。这个过程对用户是透明的,用户无需手动添加Cookie。 -
符合HTTP协议规范:根据HTTP协议的规范,浏览器有责任在每次请求时携带与该请求相关的Cookie。这是为了实现会话管理、身份验证等功能,确保用户在浏览网站时能够保持一致的状态。
4. Cookie携带的条件
-
匹配
Path和Domain属性:浏览器只会将与当前请求的URL匹配的Cookie发送给服务器。例如,如果Cookie的Domain属性是example.com,那么只有当请求的域名是example.com时,该Cookie才会被发送。 -
Cookie未过期:如果Cookie设置了
Expires或Max-Age属性,浏览器会检查Cookie是否已过期。如果已过期,浏览器不会发送该Cookie。 -
非
HttpOnly属性的Cookie:如果Cookie设置了HttpOnly属性,浏览器会阻止JavaScript访问该Cookie,但仍然会在HTTP请求中自动携带。
5. 举例说明
假设用户访问了一个网站,服务器在响应中设置了以下Cookie:
http复制
Set-Cookie: session_id=1234567890; Path=/; Max-Age=3600
Set-Cookie: theme=dark; Path=/; HttpOnly
-
存储Cookie:浏览器会将这两个Cookie存储在本地。
-
后续请求:当用户再次访问该网站时,浏览器会自动将这两个Cookie附加到请求中:
http复制
GET / HTTP/1.1 Host: example.com Cookie: session_id=1234567890; theme=dark
总结
HTTP请求会携带Cookie,是因为浏览器会自动管理Cookie的存储和发送。这是为了实现会话管理、身份验证和个性化体验等功能。浏览器会根据Cookie的Path、Domain、Expires等属性,判断哪些Cookie应该附加到当前请求中,并在每次请求时自动将它们发送给服务器。
这种机制使得用户在浏览网站时能够保持一致的状态,而无需手动管理Cookie,同时也为开发者提供了方便的方式来实现会话管理和用户跟踪。
参考资料:
-
Mozilla Developer Network - HTTP Cookies
-
RFC 6265 - HTTP State Management Mechanism
-
Google Developers - Cookies Explained
-
Stack Overflow - How do cookies work?
-
W3Schools - HTTP Cookies
相关文章:
七天免登录 为什么不能用seesion,客户端的http请求自动携带cookei的机制(比较重要)涉及HTTP规范
如果是七天免登录,和session肯定没关系,因为session不能持久化,主要是客户端一旦关闭,seesion就失效了/// 所以必须是能持久化的,这就清晰了,要莫在的服务器保存,要摸在客户端设置 cook机制 1. 使用Cookie实现七天免登录 前端(登…...
HarmonyOS:@AnimatableExtend 装饰器自学指南
在最近的项目开发中,我遇到了需要实现复杂动画效果的需求。在探索解决方案的过程中,我发现了 AnimatableExtend 装饰器,它为实现动画效果提供了一种非常灵活且强大的方式。然而,在学习这个装饰器的过程中,我发现相关的…...
主流NoSQL数据库类型及选型分析
在数据库领域,不同类型的数据库针对不同场景设计,以下是四类主流NoSQL数据库的对比分析: 一、核心特性对比 键值数据库(Key-Value) 数据模型:简单键值对存储 特点:毫秒级读写、高并发、无固定…...
kubernetes|云原生|kubeadm-1.25.7集群单master+外部etcd集群+kubeadm-init+cri-docker文件形式快速部署
一、 前言和写作原因 本文做一个kubernetes集群部署记录,实在是部署的东西太多了,害怕忘记,kubernetes集群的部署又细节比较多,因此,在这里做一个尽量详细的记录 三个VMware虚拟机,IP分别为192.168.123.…...
Qt 导入TagLib库
文章目录 0. 前言和环境介绍1. 下载TagLib2. 下载zlib3. 修改.pro文件4. 测试代码 0. 前言和环境介绍 最近在使用Qt写一个播放器,需要解析mp3文件,于是研究了一下如何导入TagLib库 Qt构建套件:Desktop Qt6.8.2 MinGW64-bit Qt Creator安装目录: D:\bit…...
新能源汽车充换站如何实现光储充一体化管理?
长三角某换电站光伏板晒到发烫,却因电网限电被迫切机;北京五环充电站每月多缴6万超容费;深圳物流车充电高峰排队3小时...当95%的充换站深陷“用不起绿电、扛不住扩容、算不清碳账”困局,安科瑞用一组真实数据撕开行业潜规则&#…...
【数据分享】2000—2024年我国省市县三级逐年归一化植被指数(NDVI)数据(年平均值/Shp/Excel格式)
之前我们分享过2000-2024年我国逐年的归一化植被指数(NDVI)栅格数据,该逐年数据是取的当年月归一化植被指数(NDVI)的年平均值。!该数据来源于NASA定期发布的MOD13A3数据集!很多小伙伴拿到数据后…...
【leetcode题解】链表
目录 链表 两数相加 两两交换链表中的节点 重排链表 合并 K 个升序链表(困难) K 个一组翻转链表 链表 1. 常用技巧 画图!!!(直观形象,便于我们理解)引入虚拟“头”节点…...
本地部署Dify 添加Ollama模型DeepSeek
1、准备工作 本地ollama 加载DeepSeek。 安装并登录Dify。 2、添加Ollama模型服务商 在设置-》模型服务上里添加Ollama模型服务商,也叫插件。 3、添加DeepSeek 使用终端命令 ollama list查询deepseek名称,如deepseek-r1:14b。 在Ollama插件冲添加…...
QEMU源码全解析 —— 块设备虚拟化(7)
接前一篇文章:QEMU源码全解析 —— 块设备虚拟化(6) 本文内容参考: 《趣谈Linux操作系统》 —— 刘超,极客时间 《QEMU/KVM源码解析与应用》 —— 李强,机械工业出版社 特此致谢! QEMU初始化阶段的块设备虚拟化 从模板生成类和类的实例化 上一回在讲解QEMU中类继承…...
图论 | 岛屿数量(深搜,广搜)
岛屿数量 acm模式:99.岛屿数量 核心代码模式: 200. 岛屿数量 思路 遍历grid,如果它是1,则通过bfs/dfs将这个小岛的grid变为0 dfs def dfs(grid,i,j):if i<0 or j<0 or i>len(grid) or j>len(grid[0]):returnif g…...
iOS:GCD信号量、同步、异步的使用方法
信号量的详细用法,可以用此方法进行队列管理 -(void)dispatchSignal{//crate的value表示,最多几个资源可访问dispatch_semaphore_t semaphore dispatch_semaphore_create(3);dispatch_queue_t quene dispatch_get_global_queue(DISPATCH_QUEUE_PRIORI…...
MSP430 Proteus 仿真作品
https://www.dong-blog.fun/post/1998 1 、 电子万年历(采用 DS1302 及 及 TC72 等芯片) 基本要求: 可显示年、月、日、星期、时、分、秒; 有温度显示功能。 发挥部分: 可调节时间和日期; 有农历显示功能 &…...
Windows打开ftp局域网共享
前提是windows已经设置好开机账号密码了,否则教程不适用 第一先打开电脑ftp共享配置 点击保存即可 2.设置要共享到其他电脑的文件路径(如果你要共享整个盘你就设置整个盘,如果是共享盘中某文件就设置某文件,这里是某文件&#x…...
基于HTML的邮件发送状态查询界面设计示例
以下是一个基于HTML的邮件发送状态查询界面设计示例,结合筛选功能、状态展示和重新发送操作,采用Bootstrap框架实现响应式布局: <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"&…...
聊聊langchain4j的MCP
序 本文主要研究一下langchain4j对Model Context Protocol (MCP) 的支持 MCP MCP协议规定了两种传输方式: HTTP:客户端请求一个SSE(Server-Sent Events)通道以从服务器接收事件,然后通过HTTP POST请求发送命令。这…...
我爱学算法之——滑动窗口攻克子数组和子串难题(中)
学习算法,继续加油!!! 一、将 x 减到 0 的最小操作数 题目解析 来看这一道题,题目给定一个数组nums和一个整数x;我们可以在数组nums的左边或者右边进行操作(x减去该位置的值)&#…...
从零开始上手huggingface
1. 环境配置 # git 安装:https://git-scm.com/ # git lfs安装:https://git-lfs.com git lfs install # huggingface-cli 安装:https://huggingface.co/docs/hub/index pip install huggingface_hub2. 网站直接下载模型 可能会中断ÿ…...
MySQL 死锁问题分析与解决方案
**** 一、死锁原因分析 死锁通常由以下场景引发: 事务执行顺序不一致:多个事务以不同顺序访问相同资源。索引缺失:全表扫描导致行锁升级为表锁。长事务或大事务:长时间持有锁资源,增加冲突概率。隔离级别设置&#x…...
用 pytorch 从零开始创建大语言模型(六):对分类进行微调
用 pytorch 从零开始创建大语言模型(六):对分类进行微调 6 微调用于分类6.1 微调的不同类别6.2 准备数据集6.3 创建数据加载器6.4 使用预训练权重初始化模型6.5 添加分类头部6.6 计算分类损失和准确率6.7 在监督数据上微调模型6.8 使用LLM进…...
dify1.1.1安装
1、 按照GitHub上操作 下载源码,没有安装git的,可以下载成zip包, unzip 解压 git clone https://github.com/langgenius/dify.git cd dify cd docker cp .env.example .env2、启动前 ,先改下 docker-compose.yaml,…...
Netty——BIO、NIO 与 Netty
文章目录 1. 介绍1.1 BIO1.1.1 概念1.1.2 工作原理1.1.3 优缺点 1.2 NIO1.2.1 概念1.2.2 工作原理1.2.3 优缺点 1.3 Netty1.3.1 概念1.3.2 工作原理1.3.3 优点 2. Netty 与 Java NIO 的区别2.1 抽象层次2.2 API 易用性2.3 性能优化2.4 功能扩展性2.5 线程模型2.6 适用场景 3. 总…...
【Linux】信号:信号保存和处理
🔥个人主页:Quitecoder 🔥专栏:linux笔记仓 目录 01.阻塞信号信号集 02.捕捉信号sigaction可重入函数volatileSIGCHLD 01.阻塞信号 实际执行信号的处理动作称为信号递达:每个信号都有一个默认行为,例如终…...
应用权限组列表
文章目录 使用须知位置相机麦克风通讯录日历运动数据身体传感器图片和视频音乐和音频跨应用关联设备发现和连接剪切板文件夹文件(deprecated) 使用须知 在申请目标权限前,建议开发者先阅读应用权限管控概述-权限组和子权限,了解相关概念,再合…...
MATLAB实现基于“蚁群算法”的AMR路径规划
目录 1 问题描述 2 算法理论 3 求解步骤 4 运行结果 5 代码部分 1 问题描述 移动机器人路径规划是机器人学的一个重要研究领域。它要求机器人依据某个或某些优化原则 (如最小能量消耗,最短行走路线,最短行走时间等),在其工作空间中找到一…...
【深度学习】多目标融合算法(五):定制门控网络CGC(Customized Gate Control)
目录 一、引言 二、CGC(Customized Gate Control,定制门控网络) 2.1 技术原理 2.2 技术优缺点 2.3 业务代码实践 2.3.1 业务场景与建模 2.3.2 模型代码实现 2.3.3 模型训练与推理测试 2.3.4 打印模型结构 三、总结 一、引言 上一…...
【NLP 42、实践 ⑪ 用Bert模型结构实现自回归语言模型的训练】
如果结局早已注定,那么过程就将大于结局 —— 25.3.18 自回归语言模型:由前文预测后文的语言模型 特点:单向 训练方式:利用前n个字预测第n1个字,实现一个mask矩阵,送入Bert模型,让其前文看不到…...
TCP | 序列号和确认号 [逐包分析] | seq / ack 详解
注 : 本文为 “TCP 序号(seq)与确认序号(ack)” 相关文章合辑。 英文引文,机翻未校。 中文引文,略作重排。 如有内容异常,请看原文。 Understanding TCP Seq & Ack Numbers […...
在Linux、Windows系统上安装开源InfluxDB——InfluxDB OSS v2并设置开机自启的保姆级图文教程
一、进入InfluxDB下载官网 InfluxData 文档https://docs.influxdata.com/Install InfluxDB OSS v2 | InfluxDB OSS v2 Documentation...
考研复习之队列
循环队列 队列为满的条件 队列为满的条件需要特殊处理,因为当队列满时,队尾指针的下一个位置应该是队头指针。但是,我们不能直接比较 rear 1 和 front 是否相等,因为 rear 1 可能会超出数组索引的范围。因此,我们需…...
