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.mzph.cn/news/733427.shtml

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

相关文章

设计模式 代理模式

代理模式主要使用了 Java 的多态&#xff0c;主要是接口 干活的是被代理类&#xff0c;代理类主要是接活&#xff0c; 你让我干活&#xff0c;好&#xff0c;我交给幕后的类去干&#xff0c;你满意就成&#xff0c;那怎么知道被代理类能不能干呢&#xff1f; 同根就成&#xff…

leetcode 估算题

2117. 一个区间内所有数乘积的缩写 class Solution {public String abbreviateProduct(int left, int right) {long c 0, suf 1, maxSuf (long) 1e11, len 0;double pre 1.0;for (int num left; num < right; num) {pre * num;suf * num;while (pre > 100000) { /…

档案室管理人员有哪些岗位

档案室管理人员的岗位可以分为以下几类&#xff1a; 1. 档案文书管理岗位&#xff1a;负责档案文书的管理、整理、归档和借阅工作&#xff0c;包括档案资料的分类、编目、装订、存储等。 2. 档案数字化管理岗位&#xff1a;负责将纸质档案数字化&#xff0c;进行扫描、转换、存…

你喜欢那种舞者呢?

迷宫中的舞者&#xff1a;程序员职业赛道的探索与魅力 在数字世界的深处&#xff0c;程序员的职业赛道宛如一座神秘而迷人的迷宫。这个迷宫中&#xff0c;每个转角都隐藏着无限的可能&#xff0c;每个领域都散发着独特的魅力。前端开发者如同花园中的精灵&#xff0c;后端工程师…

mac下终端命令提示补全

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 mac下终端命令提示补全 前言Zsh-autosuggestions原理解析&#xff1a;智能提示的工作方式1. 命令历史分析&#xff1a;2. 智能提示生成&#xff1a;3. 用户交互和选择&#xff1a;4. 配置和个性化&…

Linux基础IO【 详 解 】

文章目录 C语言文件IOC语言文件接口汇总默认打开的三个流 系统文件IOopenclosewriteread 文件描述符fd文件描述符的分配规则重定向重定向的本质dup2 FILEFILE当中的文件描述符FILE当中的缓冲区 理解文件系统初识inode磁盘分区与格式化介绍 软硬链接软链接硬链接软硬链接的区别 …

CorelDRAW Graphics Suite2024专业图形设计软件Windows/Mac最新25.0.0.230版

CorelDRAW Graphics Suite 2024是一款专业的图形设计软件&#xff0c;它集成了CorelDRAW Standard 2024和其他高级图形处理工具&#xff0c;为用户提供了全面的图形设计和编辑解决方案。 该软件拥有强大的矢量编辑功能&#xff0c;用户可以轻松创建和编辑矢量图形&#xff0c;…

UI 易用性测试 以及自动化实现!

GUI 是指图形用户界面&#xff0c;UI 是指用户界面&#xff0c;对于纯软件系统&#xff0c;这两者没有本质的区别&#xff0c;GUI易用性测试与 UI 易用性测试内容一致。但是如果测试的对象是一个产品&#xff0c;这两者则存在区别&#xff0c;对于产品 UI 则不仅仅包括 GUI&…

多线程-线程池原子性并发工具类

1.线程池 1.线程状态 虚拟机中线程的六种状态 新建状态&#xff08;NEW&#xff09; --创建线程 就绪状态&#xff08;RUNNABLE&#xff09; --start方法 阻塞状态&#xff08;BLOCKED&#xff09; --无法获得锁对象 等待状态&#xff08;WAITING&#xff09; …

springboot254小区团购管理

小区团购管理设计与实现 摘 要 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff0c;在计算机上安装小区团购管理软件来发挥其高效地信…

菜鸟笔记-14Python绘图颜色使用

Python中绘图主要依赖于各种库&#xff0c;其中matplotlib是最常用且功能强大的一个。在matplotlib中&#xff0c;你可以使用各种颜色来表示不同的数据点、线条或填充区域。下面我将详细介绍如何在Python中使用matplotlib来设置绘图颜色&#xff0c;并给出具体的例子。 14.1颜…

Spring循环依赖问题分析

对象分类&#xff1a;1.成品对象&#xff1a;实例化完成 初始化完成 2.半成品对象&#xff1a; 实例化完成 初始化未完成 实例化和初始化可以分开执行是解决循环依赖问题的关键 一级缓存&#xff1a;保存完成的bean对象 二级缓存&#xff1a;存储成品对象 三级缓存&#xff1a…

《北上广深杭》都有哪些最值得加入的互联网大厂

IT行业做技术很公平&#xff0c;没那么看重出身&#xff0c;只要你技术好&#xff0c;能力强&#xff0c;就能进大厂&#xff0c;拿高薪。IT行业算是目前为数不多的比较容易屌丝逆袭的行业之一&#xff0c;IT行业也从来不缺少造富神话。一起加油吧&#xff0c;打工人&#xff0…

Python 创建PPT

本篇为如何使用Python来创建ppt文件。 创建PPT 安装必要的库 命令如下&#xff1a; pip install python-pptx 安装过程&#xff1a; 创建ppt文件 在当前目录下创建一个test的ppt文件。其中包含两页&#xff0c;分别使用了不同的布局。 第一页设置了标题和内容。第二页只设…

【每日前端面经】2024-03-09

【每日前端面经】2024-03-09 欢迎订阅我的前端面经专栏: 每日前端面经 本期题目来源: 牛客 文件上传 传统表单上传 浏览器支持度高无需额外的 JS 代码无法自定义上传页面不适合实现高级功能页面刷新后需要重新选择文件 XMLHttpRequest对象 const fileInput document.getEl…

【Linux】cpp-httplib库

目录 升级gcc版本 下载cpp-httplib的zip安装包&#xff0c;上传到服务器 ​编辑 简单使用 首先打开gittee,搜索cpp-httplib,选择其中一个即可 也可以点下方链接 cpp-httplib库&#xff1a;cpp-httplib: cpp-httplib (gitee.com) 注意&#xff1a;cpp-httplib在使用的时候需…

大数据开发(Spark面试真题-卷三)

大数据开发&#xff08;Spark面试真题&#xff09; 1、Spark的阶段划分&#xff1f;2、Sparkjoin的分类&#xff1f;3、Spark map join的实现原理&#xff1f;4、介绍下Spark Shuffle及其优缺点&#xff1f;5、什么情况下产生Spark Shuffle&#xff1f;6、Spark为什么适合迭代处…

2024年AI辅助研发:技术进展与行业应用展望

随着人工智能技术的迅猛发展&#xff0c;AI辅助研发已成为科技界和工业界的热门话题。在本文中&#xff0c;我们将探讨2024年AI辅助研发的技术进展、行业应用案例、面临的挑战与机遇&#xff0c;以及未来的趋势预测。 技术进展与研发效率提升 2024年&#xff0c;AI在研发领域…

AJAX-HTTP协议

文章目录 HTTP协议请求报文响应报文接口文档 HTTP协议 规定了浏览器发送及服务器返回内容的格式 请求报文 浏览器按照HTTP协议要求的格式&#xff0c;发送给服务器的内容 组成部分&#xff1a; 1.请求行&#xff1a;请求方法&#xff0c;URL&#xff0c;协议 2.请求头&#…

解释c++wait()和notify()

在 C 中&#xff0c;wait() 和 notify() 是与条件变量&#xff08;std::condition_variable&#xff09;一起使用的方法&#xff0c;用于线程间的同步与通信。 wait(): 当一个线程调用 wait() 方法时&#xff0c;它会释放锁并进入 blocked 状态&#xff0c;等待另一个线程调用 …