SpringBoot Cookie & Session 用户登录及登录状态保持功能实现代码
作者:q***4986
文章主要内容介绍了会话跟踪技术,包括会话建立、结束、会话跟踪定义以及客户端和服务端会话跟踪技术(如Cookie和Session令牌技术),文章详细描述了Session的使用场景、工作原理、常用方法和认证流程,感兴趣的朋友一起看看吧
会话技术
- 功能:提供用户登陆成功后的登陆标记 (一次登录,一段时间都登录)
- 会话
- 定义:包含一次或多次请求和响应的访问操作
- 建立会话:用户打开浏览器访问 Web 服务器资源时建立会话
- 结束会话:一方断开连接时结束会话
- 会话跟踪
- 定义:一种维护浏览器状态的方法
- 功能:服务器通过会话跟踪来识别多次请求是否来自于同一浏览器
- 同一次会话的多次请求间共享数据
- 会话跟踪方案
客户端会话跟踪技术 : Cookie

服务端会话跟踪技术 : Session

令牌技术(token)
令牌 : 用户身份的标识,实际上就是一个字符串
Cookie
定义:浏览器访问服务器后,服务器传给浏览器的一段数据,由浏览器保存,后续通信中浏览器也要将 Cookie 发送给服务器功能- 识别用户身份 (uid)
- 存储用户偏好:让浏览器记住这位访客的特定信息
工作条件- 浏览器每次访问该服务器,都必须带上 Cookie
- 浏览器需要保存 Cookie,不得轻易删除
- 不能跨域
工作流程- 客户端提交一个HTTP请求给服务端
- 服务端 Set-Cookie,同时提交响应内容给客户端
- 客户端再次向服务器请求,并在请求头中携带一个Cookie
有效期- Expire 值:Cookie 在生成时就会被指定一个 Expire 值,这就是 Cookie 的生存周期
- 立即清除 Cookie:生存周期设置为 “0” 或负值,这样在关闭浏览器时,就马上清除 Cookie,不会记录用户信息,更加安全
缺点- 数量限制:一个浏览器能创建的 Cookie 数量最多为 300 个,并且每个不能超过 4KB,每个 Web 站点能设置的 Cookie 总数不能超过 20 个
- 安全性低:存在跨站点脚本攻击的可能,脚本指令可以读取当前站点的所有 Cookie 内容,并且可以提交到指定服务器重现其功能
问:为什么需要 Cookie 答:web程序使用的HTTP协议是无状态的协议,对于事务处理没有记忆能力,如果后续处理需要前面的信息则必须重传,导致每次连接传送的数据量增大
Session
一、概述
定义- Session (会话控制),Session 对象存储特定用户会话所需的属性及配置信息
- SessionID:客户端第一次请求服务器时,服务器为客户端算出的一个值,存储在 Cookie 中,用于定位用户 Session 在服务器中的位置
- 与 Cookie 的区别:Cookie 可以通过伪造来实现登录并进行一些 HTTP 请求,从安全性上来讲,Session 比 Cookie 安全性稍微高一些
功能:提高安全性有效期:一般为半小时,可以根据需求设定缺点:Session 是存储在服务器当中的,所以 Session 过多,会对服务器产生压力
二、相关工具类
HttpSession- 定义:javax.servlet.http.HttpSession 类,是 JavaWeb 自带的工具类
- 常用方法
- 命令
- 功能
- getAttribute(“attributeName”)
- 获取指定名称的属性值
- setAttribute(“attributeName”, myAttributeObject)
- 设置指定名称的属性值
DTO:Data Transfer Object,在 Session 中的 MyClass 应该去掉敏感信息,转为 MyClassDTO 进行传输
三、认证流程
工作流程
- 创建 Session :用户第一次请求服务器的时候,服务器根据用户提交的相关信息,创建对应的 Session
- 响应 Session ID:服务器响应请求时,将此 Session 的唯一标识信息 SessionID 返回给浏览器
- 存入 Cookie:浏览器接收到服务器返回的 SessionID 信息后,将此信息存入到 Cookie 中,同时 Cookie 记录此 SessionID 属于哪个域名
- 携带 Cookie:当用户第二次访问服务器的时候,请求会自动判断此域名下是否存在 Cookie 信息
- 存在 Cookie → 自动将 Cookie 信息也发送给服务端,服务端会从 Cookie 中获取 SessionID,再根据 SessionID 查找对应的 Session 信息
- 找到 Session → 证明用户已经登录可执行后面操作
- 未找到 Session → 可能是已过期的 Session 或者是假 Cookie
- 不存在 Cookie → 说明用户没有登录或者登录失效
- 存在 Cookie → 自动将 Cookie 信息也发送给服务端,服务端会从 Cookie 中获取 SessionID,再根据 SessionID 查找对应的 Session 信息
原理说明
- 登录:客户端提交登录表单
- 校验:服务器进行登录校验(如果校验失败在直接抛出异常)
- 获取 Session 对象
- Request 中已经有 Session → 获取 HttpSession 对象
- Request 中还没有 Session → 创建 HttpSession 对象,并生成唯一标识符(SessionId)
- request.getSession() // 如果 request 中有 session 则获取
- 更新登录状态:将用户对象 user 以 USER_LOGIN_STATE 为键存储在该 HttpSession 中
- USER_LOGIN_STATE 是一个常量,用来标识用户登录状态
- request.getSession().setAttribute(USER_LOGIN_STATE, user); // 更新Session登录状态
- 设置过期时间:设置该 HttpSession 的过期时间为 1 小时(即 1 小时如果内没有与该 HttpSession 关联的请求,该 HttpSession 将被自动销毁)
request.getSession().setMaxInactiveInterval(60 * 60); // 设定Session过期时间
- 回传 SessionId:服务器将 SessionId 写入 Response Headers 中的 Set-Cookie
HTTP/1.1 200 OK Set-Cookie: JSESSIONID=1234567890ABCDEF; Path=/; HttpOnly
- 保存 SessionId:客户端将 SessionId 存储在 Cookie 中
- 客户端请求资源:客户端登录后,每次访问服务器都会将 SessionId 写在 请求头的 Cookie 属性中
GET /some/resource HTTP/1.1 Host: www.example.com Cookie: JSESSIONID=1234567890ABCDEF
四、示例
实现逻辑
创建 DTO 类- 创建 com.projectname.dto.UserDTO 类
- 定义 UserDTO 类中的属性 (希望展示的 User 的属性)
创建 UserHolder 工具类- 创建 com.projectname.utils.UserHolder 类
- 定义 ThreadLocal 本地线程 tl
- 定义 save / get / remove 方法
修改 UserServiceImpl 中的返回值- 调用 hutools 的 BeanUtil 工具类,使用其 copyProperties(User, UserDTO.class) 方法进行 DTO 映射
- 修改 session 中的返回值 (User → UserDTO)
- session.setAttribute(”User”, BeanUtil.copyProperties( user, UserDTO.class)
修改 UserController 中的返回值- UserDTO user = UserHolder.getUser();
- 创建拦截器
- 获取用户请求的 Token 或其他标识
- 验证 Token,并解析出用户信息
- 将用户信息存入
UserHolder - 在请求完成后清除
UserHolder的数据,防止内存泄漏
- 配置拦截器:注册拦截器,让其拦截需要验证的路径
示例代码
UserDTO 类(com.projectname.dto.UserDTO)
// com.projectname.dto.UserDTO
@Data
public class UserDTO {
private Long id;
private String nickName;
private String icon;
}
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();
}
}- 拦截器(com.myproject.config.UserInterceptor.java)
- 目标:自动拦截所有请求,如果有用户信息则存入 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 无效或解析失败
}}
- 配置拦截器
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private UserInterceptor userInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(userInterceptor) // 注册拦截器
.addPathPatterns("/**") // 拦截所有路径
.excludePathPatterns("/login", "/register"); // 排除登录、注册等公开路径
}
}到此这篇关于SpringBoot Cookie & Session 用户登录及登录状态保持功能实现代码的文章就介绍到这了,更多相关springboot cookie session用户登录内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
