Session登陆实践

Session登陆实践

Session登录是一种常见的Web应用程序身份验证和状态管理机制。当用户成功登录到应用程序时,服务器会为其创建一个会话(session),并在会话中存储有关用户的信息。这样,用户在与应用程序交互的整个会话期间都可以被识别,并且可以维护其状态。

img

以下是Session登录的基本流程:

  1. 用户提交登录请求: 用户在应用程序的登录页面输入用户名和密码,然后提交登录表单。
  2. 服务器验证身份: 应用程序服务器接收到登录请求后,会验证用户提供的用户名和密码是否匹配数据库中存储的凭据。如果验证成功,将进入下一步;否则,用户将收到身份验证失败的通知。
  3. 创建Session: 一旦用户身份验证成功,服务器会为该用户创建一个唯一的会话标识符(Session ID)。通常,这个Session ID会被存储在用户的浏览器中,例如通过Cookie或URL参数的方式。
  4. 存储用户信息: 服务器将与用户相关的信息(如用户ID、角色等)存储在该Session中。这些信息可以在整个会话期间用于标识用户和维护其状态。
  5. 返回登录成功响应: 服务器向用户的浏览器返回登录成功的响应,可能包括一些用户信息或重定向到用户的个人资料页面。
  6. 保持会话状态: 在用户与应用程序交互的过程中,服务器会根据Session ID识别用户,并使用存储在Session中的信息来维护用户的状态。这可以包括用户的登录状态、权限、购物车内容等。
  7. 注销处理: 用户在应用程序中选择注销时,服务器会销毁与用户关联的Session,用户需要重新进行身份验证才能再次访问受保护的资源。

单机Session登陆

单机(单节点)Session登录是指在单一服务器环境中进行用户身份验证和会话管理的方式。这种情况下,用户的身份信息和会话状态仅存储在单个服务器上,而不涉及多个服务器之间的共享

实践

以下案例基于SpringBoot

Controller
@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {/*** 用户登录** @param userLoginRequest* @param request* @return*/@PostMapping("/login")public BaseResponse<UserVO> userLogin(@RequestBody UserLoginRequest userLoginRequest, HttpServletRequest request) {if (userLoginRequest == null) {throw new BusinessException(ErrorCode.PARAMS_ERROR);}String userAccount = userLoginRequest.getUserAccount();String userPassword = userLoginRequest.getUserPassword();if (StringUtils.isAnyBlank(userAccount, userPassword)) {throw new BusinessException(ErrorCode.PARAMS_ERROR);}User user = userService.userLogin(userAccount, userPassword, request);UserVO userVO = new UserVO();BeanUtils.copyProperties(user, userVO);return ResultUtils.success(userVO);}/*** 用户注销** @param request* @return*/@PostMapping("/logout")public BaseResponse<Boolean> userLogout(HttpServletRequest request) {if (request == null) {throw new BusinessException(ErrorCode.PARAMS_ERROR);}boolean result = userService.userLogout(request);return ResultUtils.success(result);}}
Service
/*** 用户登陆*/
@Override
public User userLogin(String userAccount, String userPassword, HttpServletRequest request) {// 1. 校验if (StringUtils.isAnyBlank(userAccount, userPassword)) {throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数为空");}if (userAccount.length() < 4) {throw new BusinessException(ErrorCode.PARAMS_ERROR, "账号错误");}if (userPassword.length() < 8) {throw new BusinessException(ErrorCode.PARAMS_ERROR, "密码错误");}// 2. 加密String encryptPassword = DigestUtils.md5DigestAsHex((SALT + userPassword).getBytes());// 查询用户是否存在QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.eq("userAccount", userAccount);queryWrapper.eq("userPassword", encryptPassword);User user = userMapper.selectOne(queryWrapper);// 用户不存在if (user == null) {log.info("user login failed, userAccount cannot match userPassword");throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户不存在或密码错误");}// 3. 记录用户的登录态 request.getSession().setAttribute(USER_LOGIN_STATE, user); // USER_LOGIN_STATE是常量可自定义return user;
}/*** 用户注销** @param request*/
@Override
public boolean userLogout(HttpServletRequest request) {if (request.getSession().getAttribute(USER_LOGIN_STATE) == null) {throw new BusinessException(ErrorCode.OPERATION_ERROR, "未登录");}// 移除登录态request.getSession().removeAttribute(USER_LOGIN_STATE);return true;
}/*** 获取当前登录用户** @param request* @return*/
@Override
public User getLoginUser(HttpServletRequest request) {// 先判断是否已登录Object userObj = request.getSession().getAttribute(USER_LOGIN_STATE);User currentUser = (User) userObj;if (currentUser == null || currentUser.getId() == null) {throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);}// 从数据库查询(追求性能的话可以注释,直接走缓存)long userId = currentUser.getId();currentUser = this.getById(userId);if (currentUser == null) {throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);}return currentUser;
}
流程解答

HttpServletRequest 中的 Session 是一个表示用户会话的对象,它属于Java Servlet API 中的 HttpSession 接口。HttpSession 提供了一种在请求之间存储和检索用户特定数据的方式,允许在整个用户会话期间保持状态信息。

HttpServletRequest中,你可以通过调用getSession()方法来获取与当前请求相关联的HttpSession对象。例如:

HttpSession session = request.getSession();

getSession()方法会检查请求中是否存在与会话相关的标识符(通常是Cookie中的JSESSIONID),如果存在,则返回与该标识符相关联的HttpSession对象;如果不存在,则创建一个新的HttpSession对象,并在响应中将新的会话标识符(JSESSIONID)发送给客户端。

HttpSession的结构是一个键值对的存储结构,类似于一个Map。你可以使用setAttributegetAttribute方法来设置和获取会话中的属性。例如:

// 设置会话属性
session.setAttribute("USER_LOGIN_STATE", "userId");// 获取会话属性
String userId = (String) session.getAttribute("USER_LOGIN_STATE");

这里的会话属性是根据键值对存储在HttpSession中的,你可以根据需要在会话中存储和检索数据,以便在用户的整个会话期间保持状态。

会话通常在用户访问应用程序时被创建。当用户首次访问应用程序时,Servlet容器会为其创建一个新的HttpSession对象,并将其与请求关联。这个会话对象将持续存在,直到会话过期、用户注销或关闭浏览器。会话的过期时间可以通过配置进行调整。

总而言之,HttpServletRequest中的Session是一个HttpSession对象,它在用户访问应用程序时被创建,用于在请求之间共享和保持用户状态信息。

设置Sesion有效期

在项目的Resource目录下的application.ymlapplication.properties中修改配置

spring:#session的失效时间 86400s = 1天session:timeout: 86400

分布式Session登陆

单机模式下,不同的Session对象都被保存在同一个服务器中,服务器根据保存在用户浏览器Cookie中的SessionId查找Session对象

假如我们的服务端是分布式的,也就是有多台服务器同时提供服务,假如在用户登陆请求发送到服务器A,服务器A保存了<SessionId, 用户Id>;突然服务器A宕机,接下来当前用户的所有请求将要发送到服务器B,但此时服务器B中没有当前保存当前用户的登陆态,显然单机Session登陆不太适合分布式下的用户登陆

解决方案

单机Session登陆的局限在于,Session保存在一台服务器上,其他服务器无法获取用户是否登陆;那么把用户登陆的Session保存在所有服务器都能获取的地方不久好了嘛

这里介绍最常用的解决方案也就是使用Redis存储Session

实践

将单机Session登陆改为分布式Session登陆只需要以下配置👇

需要安装Redis,这里就不介绍怎么安装了,可自行上网搜索

在项目的pom.xml文件中引入依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency><groupId>org.springframework.session</groupId><artifactId>spring-session-data-redis</artifactId>
</dependency>

spring-boot-starter-data-redis 是SpringBoot简化操作Redis的依赖,spring-session-data-redis是简化将Session保存在Redis 的依赖

在项目的Resource目录下的application.ymlapplication.properties中修改配置

spring:session:storeType: redis # 使用Redis存储Sessiontimeout: 86400 #session的失效时间 86400s = 1天redis:port: 6379 #Redis所在的端口号host: xxx.xxx.xxx.xxx # Redis的远程地址,部署在单机可以写localhostdatabase: 0password: xxx #Redis没有密码,可以删除此行

只需要添加依赖和修改一下配置即可将单机Session登陆改为分布式Session登陆,这就是SpringBoot的强大之处🐮

此时我们登陆一下就可以看见Redis中存储了用户的Session

在这里插入图片描述
在这里插入图片描述
如果觉得本篇文章对您有帮助,可否点个小赞😺;篇幅较长建议收藏🫠;关注一手等待后续更新更多干货🚀

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

鸿蒙Harmony应用开发—ArkTS声明式开发(模态转场设置:全屏模态转场)

通过bindContentCover属性为组件绑定全屏模态页面&#xff0c;在组件插入和删除时可通过设置转场参数ModalTransition显示过渡动效。 说明&#xff1a; 从API Version 10开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 不支持横竖屏切换。…

【CSharp】线程间操作无效,从不是创建控件XXX的线程访问它的解决办法

【CSharp】线程间操作无效,从不是创建控件XXX的线程访问它的解决办法 1.背景2.问题3.解决办法 1.背景 我的项目是 Windows窗体应用&#xff08; .NET Framework)。 在 C# 中&#xff0c;窗体&#xff08;Windows Form&#xff09;的 UI 元素通常在创建它们的主线程上进行访问…

【软考】设计模式之享元模式

目录 1. 说明2. 应用场景3. 结构图4. 构成5. 适用性6. java示例 1. 说明 1.享元设计模式&#xff08;Flyweight Design Pattern&#xff09;是一种常见的软件设计模式2.属于结构型设计模式&#xff0c;对象结构型模式3.目的&#xff1a;运用共享技术有效地支持大量细粒度的对象…

力扣日记3.6-【回溯算法篇】51. N 皇后

力扣日记&#xff1a;【回溯算法篇】51. N 皇后 日期&#xff1a;2023.3.6 参考&#xff1a;代码随想录、力扣 51. N 皇后 题目描述 难度&#xff1a;困难 按照国际象棋的规则&#xff0c;皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。 n 皇后问题 研究的是如何将…

智能工具管理系统-智能工具柜系统

智能工具可视化管理系统(智工具DW-S308)是依托互3D技术、云计算、大数据、RFID技术、数据库技术、AI、视频分析技术对RFID工具进行统一管理、分析的信息化、智能化、规范化的系统。 一、工具管理现状 东识RFID工具管理系统是一种便捷化的工具管理系统&#xff0c;它采用RFID技…

一篇搞懂什么是LRU缓存|一篇搞懂LRU缓存的实现|LRUCache详解和实现

LRUCache 文章目录 LRUCache前言项目代码仓库什么时候会用到缓存(Cache)缓存满了&#xff0c;怎么办&#xff1f;什么是LRUCacheLRUCache的实现LRUCache对应的OJ题实现LRUCache对应的STL风格实现 前言 这里分享我的一些博客专栏&#xff0c;都是干货满满的。 手撕数据结构专栏…

【UE5】游戏框架GamePlay

项目资源文末百度网盘自取 游戏框架 游戏 由 游戏模式(GameMode) 和 游戏状态(GameState) 所组成 加入游戏的 人类玩家 与 玩家控制器(PlayerController) 相关联 玩家控制器允许玩家在游戏中拥有 HUD&#xff0c;这样他们就能在关卡中拥有物理代表 玩家控制器还向玩家提供 …

Spring boot 请求参数包含[]等特殊字符,导致无法接收问题

前言对字符进行转义修改tomcat 配置 前言 Spring boot 请求参数包含[]等特殊字符&#xff0c;导致无法接收问题 对字符进行转义 中括号[] 必须用%5B%5D转义&#xff0c;否则tomcat无法解析&#xff0c;回抛出不合法字符异常&#xff0c;不会进入控制器 修改tomcat 配置 p…

安信可IDE(AiThinker_IDE)编译ESP8266工程方法

0 工具准备 AiThinker_IDE.exe ESP8266工程源码 1 安信可IDE&#xff08;AiThinker_IDE&#xff09;编译ESP8266工程方法 1.1 解压ESP8266工程文件夹 我们这里使用的是NON-OS_SDK&#xff0c;将NON-OS_SDK中的1_UART文件夹解压到工作目录即可 我这里解压到了桌面&#xff0c…

模拟框图的表示

微分方程的建立 目的&#xff1a;为建立LTI系统的数学模型&#xff0c;需要列写微分方程式。 以RLC电路为例&#xff1a; 以Us为输入&#xff0c;Uc为输入&#xff0c;则可以得出以下微分方程式&#xff1a; 抽去物理意义后&#xff0c;得到一般的常微分线性方程&#xff1a;…

朗伯特球腔均匀光源积分球

均匀光源积分球&#xff0c;又称照度积分球或光度球、光通球&#xff0c;是光电测试中常用的一种工具。它是一个中空的球体&#xff0c;内壁涂有一层平整的漫反射材料&#xff0c;通常由金属或陶瓷制成。积分球的主要功能是收集光并将其作为散射光源或测量光源使用。 积分球的工…

【Python】Python Astar算法生成最短路径GPS轨迹

简介 最短路径问题是计算机科学中一个经典问题&#xff0c;它涉及找到图中两点之间距离最短的路徑。在实际应用中&#xff0c;最短路径算法用于解决广泛的问题&#xff0c;例如导航、物流和网络优化。 步骤 1&#xff1a;加载道路网络数据 要计算最短路径&#xff0c;我们需…