news 2026/5/4 23:51:33

SpringBoot - Cookie Session 用户登录及登录状态保持功能实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SpringBoot - Cookie Session 用户登录及登录状态保持功能实现

会话技术

  1. 功能:提供用户登陆成功后的登陆标记 (一次登录,一段时间都登录)
  2. 会话
    1. 定义:包含一次或多次请求和响应的访问操作
    2. 建立会话:用户打开浏览器访问 Web 服务器资源时建立会话
    3. 结束会话:一方断开连接时结束会话
  3. 会话跟踪
    1. 定义:一种维护浏览器状态的方法
    2. 功能:服务器通过会话跟踪来识别多次请求是否来自于同一浏览器
    3. 同一次会话的多次请求间共享数据
  4. 会话跟踪方案
    1. 客户端会话跟踪技术 :Cookie

    2. 服务端会话跟踪技术 :Session

    3. 令牌技术(token)

      令牌: 用户身份的标识,实际上就是一个字符串


Cookie

  1. 定义:浏览器访问服务器后,服务器传给浏览器的一段数据,由浏览器保存,后续通信中浏览器也要将 Cookie 发送给服务器
  2. 功能
    1. 识别用户身份 (uid)
    2. 存储用户偏好:让浏览器记住这位访客的特定信息
  3. 工作条件
    1. 浏览器每次访问该服务器,都必须带上 Cookie
    2. 浏览器需要保存 Cookie,不得轻易删除
    3. 不能跨域
  4. 工作流程
    1. 客户端提交一个HTTP请求给服务端
    2. 服务端 Set-Cookie,同时提交响应内容给客户端
    3. 客户端再次向服务器请求,并在请求头中携带一个Cookie
  5. 有效期
    1. Expire 值:Cookie 在生成时就会被指定一个 Expire 值,这就是 Cookie 的生存周期
    2. 立即清除 Cookie:生存周期设置为 “0” 或负值,这样在关闭浏览器时,就马上清除 Cookie,不会记录用户信息,更加安全
  6. 缺点
    1. 数量限制:一个浏览器能创建的 Cookie 数量最多为 300 个,并且每个不能超过 4KB,每个 Web 站点能设置的 Cookie 总数不能超过 20 个
    2. 安全性低:存在跨站点脚本攻击的可能,脚本指令可以读取当前站点的所有 Cookie 内容,并且可以提交到指定服务器重现其功能

问:为什么需要 Cookie 答:web程序使用的HTTP协议是无状态的协议,对于事务处理没有记忆能力,如果后续处理需要前面的信息则必须重传,导致每次连接传送的数据量增大


Session

一、概述

  1. 定义
    1. Session (会话控制),Session 对象存储特定用户会话所需的属性及配置信息
    2. SessionID:客户端第一次请求服务器时,服务器为客户端算出的一个值,存储在 Cookie 中,用于定位用户 Session 在服务器中的位置
  2. 与 Cookie 的区别:Cookie 可以通过伪造来实现登录并进行一些 HTTP 请求,从安全性上来讲,Session 比 Cookie 安全性稍微高一些
  3. 功能:提高安全性
  4. 有效期:一般为半小时,可以根据需求设定
  5. 缺点:Session 是存储在服务器当中的,所以 Session 过多,会对服务器产生压力

二、相关工具类

  1. HttpSession

    1. 定义:javax.servlet.http.HttpSession 类,是 JavaWeb 自带的工具类

    2. 常用方法

      命令

      功能

      getAttribute(“attributeName”)

      获取指定名称的属性值

      setAttribute(“attributeName”, myAttributeObject)

      设置指定名称的属性值

  2. DTO:Data Transfer Object,在 Session 中的 MyClass 应该去掉敏感信息,转为 MyClassDTO 进行传输

三、认证流程

工作流程
  1. 创建 Session :用户第一次请求服务器的时候,服务器根据用户提交的相关信息,创建对应的 Session
  2. 响应 Session ID:服务器响应请求时,将此 Session 的唯一标识信息 SessionID 返回给浏览器
  3. 存入 Cookie:浏览器接收到服务器返回的 SessionID 信息后,将此信息存入到 Cookie 中,同时 Cookie 记录此 SessionID 属于哪个域名
  4. 携带 Cookie:当用户第二次访问服务器的时候,请求会自动判断此域名下是否存在 Cookie 信息
    1. 存在 Cookie → 自动将 Cookie 信息也发送给服务端,服务端会从 Cookie 中获取 SessionID,再根据 SessionID 查找对应的 Session 信息
      1. 找到 Session → 证明用户已经登录可执行后面操作
      2. 未找到 Session → 可能是已过期的 Session 或者是假 Cookie
    2. 不存在 Cookie → 说明用户没有登录或者登录失效
原理说明
  1. 登录:客户端提交登录表单

  2. 校验:服务器进行登录校验(如果校验失败在直接抛出异常)

  3. 获取 Session 对象

    1. Request 中已经有 Session → 获取 HttpSession 对象

    2. Request 中还没有 Session → 创建 HttpSession 对象,并生成唯一标识符(SessionId)

      request.getSession() // 如果 request 中有 session 则获取

  4. 更新登录状态:将用户对象 user 以 USER_LOGIN_STATE 为键存储在该 HttpSession 中

    1. USER_LOGIN_STATE 是一个常量,用来标识用户登录状态

      request.getSession().setAttribute(USER_LOGIN_STATE, user); // 更新Session登录状态

  5. 设置过期时间:设置该 HttpSession 的过期时间为 1 小时(即 1 小时如果内没有与该 HttpSession 关联的请求,该 HttpSession 将被自动销毁)

    request.getSession().setMaxInactiveInterval(60 * 60); // 设定Session过期时间
  6. 回传 SessionId:服务器将 SessionId 写入 Response Headers 中的 Set-Cookie

    HTTP/1.1 200 OK Set-Cookie: JSESSIONID=1234567890ABCDEF; Path=/; HttpOnly
  7. 保存 SessionId:客户端将 SessionId 存储在 Cookie 中

  8. 客户端请求资源:客户端登录后,每次访问服务器都会将 SessionId 写在 请求头的 Cookie 属性中

    GET /some/resource HTTP/1.1 Host: www.example.com Cookie: JSESSIONID=1234567890ABCDEF

四、示例

实现逻辑
  1. 创建 DTO 类

    1. 创建 com.projectname.dto.UserDTO 类
    2. 定义 UserDTO 类中的属性 (希望展示的 User 的属性)
  2. 创建 UserHolder 工具类

    1. 创建 com.projectname.utils.UserHolder 类
    2. 定义 ThreadLocal 本地线程 tl
    3. 定义 save / get / remove 方法
  3. 修改 UserServiceImpl 中的返回值

    1. 调用 hutools 的 BeanUtil 工具类,使用其 copyProperties(User, UserDTO.class) 方法进行 DTO 映射

    2. 修改 session 中的返回值 (User → UserDTO)

      session.setAttribute(”User”, BeanUtil.copyProperties( user, UserDTO.class)

  4. 修改 UserController 中的返回值

    1. UserDTO user = UserHolder.getUser();
  5. 创建拦截器

    1. 获取用户请求的 Token 或其他标识
    2. 验证 Token,并解析出用户信息
    3. 将用户信息存入UserHolder
    4. 在请求完成后清除UserHolder的数据,防止内存泄漏
  6. 配置拦截器:注册拦截器,让其拦截需要验证的路径

示例代码
  1. UserDTO 类(com.projectname.dto.UserDTO)

    // com.projectname.dto.UserDTO @Data public class UserDTO { private Long id; private String nickName; private String icon; }
  2. UserHolder 类(com.myproject.utils.UserHolder.java)

    // com.projectname.utils.UserHolder public class UserHolder { private static final ThreadLocal<UserDTO> tl = new ThreadLocal<>(); public static void saveUser(UserDTO user){ tl.set(user); } public static UserDTO getUser(){ return tl.get(); } public static void removeUser(){ tl.remove(); } }
  3. 拦截器(com.myproject.config.UserInterceptor.java)

    1. 目标:自动拦截所有请求,如果有用户信息则存入 UserHolder 中

      @Component
      public class UserInterceptor implements HandlerInterceptor {

      @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 1. 从请求头中获取 Token,如果没有 Token 则跳过拦截器(可能是未登录状态) String token = request.getHeader("Authorization"); if (!StringUtils.hasText(token)) { return true; } // 2. 校验 Token 并解析用户信息(此处简单模拟,实际应调用 Token 验证服务或工具类) UserDTO user = validateTokenAndGetUser(token); if (user == null) { // 如果解析失败,允许继续(未登录状态) return true; } // 3. 将用户信息保存到 UserHolder 中 UserHolder.setUser(user); return true; } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // 请求处理完成后清理 ThreadLocal,防止内存泄漏 UserHolder.clear(); } // 模拟 Token 校验并获取用户信息 private UserDTO validateTokenAndGetUser(String token) { // 示例:模拟解析 Token 获取用户 if ("valid-token".equals(token)) { return getUserByToken(token); } return null; // Token 无效或解析失败 }

      }

  4. 配置拦截器

    @Configuration public class WebConfig implements WebMvcConfigurer { @Autowired private UserInterceptor userInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(userInterceptor) // 注册拦截器 .addPathPatterns("/**") // 拦截所有路径 .excludePathPatterns("/login", "/register"); // 排除登录、注册等公开路径 } }

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/30 16:07:21

解决JLink驱动下载后固件降级的操作方法

JLink驱动下载后固件降级&#xff1f;别慌&#xff0c;手把手教你恢复并彻底规避风险 在嵌入式开发的世界里&#xff0c;J-Link几乎是每个工程师的“老伙计”。它速度快、兼容性强、支持芯片广&#xff0c;是调试ARM Cortex-M系列MCU的首选工具。但即便是再可靠的设备&#xf…

作者头像 李华
网站建设 2026/4/23 2:30:11

PDF-Extract-Kit部署案例:学术期刊元数据提取系统

PDF-Extract-Kit部署案例&#xff1a;学术期刊元数据提取系统 1. 引言 1.1 业务场景描述 在科研与出版领域&#xff0c;大量学术资源以PDF格式存在&#xff0c;尤其是期刊论文、会议文章和学位论文。这些文档中蕴含丰富的结构化信息——如标题、作者、摘要、公式、表格等元数…

作者头像 李华
网站建设 2026/4/28 12:35:08

科哥PDF-Extract-Kit最佳实践:企业文档数字化解决方案

科哥PDF-Extract-Kit最佳实践&#xff1a;企业文档数字化解决方案 1. 引言&#xff1a;企业文档数字化的挑战与PDF-Extract-Kit的价值 在当今企业信息化进程中&#xff0c;大量历史文档以PDF或扫描图像形式存在&#xff0c;这些非结构化数据难以直接用于数据分析、知识管理或…

作者头像 李华
网站建设 2026/5/2 7:30:11

PDF-Extract-Kit进阶教程:自定义模型训练与微调

PDF-Extract-Kit进阶教程&#xff1a;自定义模型训练与微调 1. 引言 1.1 技术背景 在文档数字化和信息提取领域&#xff0c;PDF 文件因其格式稳定、跨平台兼容性强而被广泛使用。然而&#xff0c;传统方法难以高效处理复杂版式&#xff08;如科研论文、财务报表&#xff09;…

作者头像 李华
网站建设 2026/5/1 5:33:54

18.C++入门:stack和queue|priority_queue|容器适配器|deque

stack的介绍和使用 stack的介绍 stack的文档介绍j stack的使用 函数说明接口说明stack()构造空的栈empty()检测 stack 是否为空size()返回 stack 中元素的个数top()返回栈顶元素的引用push()将元素 val 压入 stack 中pop()将 stack 中尾部的元素弹出 155. 最小栈 - 力扣&a…

作者头像 李华
网站建设 2026/4/30 7:55:58

HY-MT1.5翻译模型入门必看:术语干预与上下文翻译详解

HY-MT1.5翻译模型入门必看&#xff1a;术语干预与上下文翻译详解 1. 引言&#xff1a;腾讯开源的混元翻译新标杆 随着全球化进程加速&#xff0c;高质量、低延迟的机器翻译需求日益增长。传统翻译模型在专业术语一致性、多语言混合场景和上下文连贯性方面常表现不佳&#xff…

作者头像 李华