【Redis】基于Redis实现共享Session登录

 用户登录是一种常用功能。这里记录一下基于Redis实现用户登录的代码。
 下面是登录的流程图:

  • 用户先提交手机号和验证码,服务器以手机号为key校验redis中存储的验证码,存在,则查询数据库中是否存在用户,不存在则创建并将token作为key,用户信息作为value保存在Redis中。
  • 用户登录成功后的请求需要在session中携带token,来进行身份的鉴权。
    在这里插入图片描述

1.用户短信验证码登录、注册代码

  • Controller层
	/*** 登录功能* @param loginForm 登录参数,包含手机号、验证码;或者手机号、密码*/@PostMapping("/login")public Result login(@RequestBody LoginFormDTO loginForm, HttpSession session){// TODO 实现登录功能return userService.login(loginForm, session) ;}
  • Service层
	@Overridepublic Result login(LoginFormDTO loginForm, HttpSession session) {String phone = loginForm.getPhone();// 1. 校验手机号if(RegexUtils.isPhoneInvalid(phone)){return Result.fail("手机号格式不正确");}//  2. 从Redis获取验证码String cacheCode = stringRedisTemplate.opsForValue().get(LOGIN_CODE_KEY + phone);String code = loginForm.getCode();if(cacheCode == null || !cacheCode.equals(code)){// 3. 不一致报错return Result.fail("验证码错误");}// 4. 一致根据手机号查用户User user = query().eq("phone", phone).one();if(user == null){// 5. 用户不存在user = createUserWithPhone(phone);// 6. 不存在创建用户}// 7. 保存用户信息到session// 7.1 生成tokenString token = UUID.randomUUID().toString(true);// 7.2 保存到redis,hash存储,使用Map减少与服务器交互次数UserDTO userDTO = BeanUtil.copyProperties(user, UserDTO.class);// 将所有字段转为stringMap<String, Object> userMap = BeanUtil.beanToMap(userDTO, new HashMap<>(),CopyOptions.create().setIgnoreNullValue(true).setFieldValueEditor((fileName,fileValue)->fileValue.toString()));// 7.3 存储stringRedisTemplate.opsForHash().putAll(LOGIN_USER_KEY+token,userMap);// 7.4 设置过期时间stringRedisTemplate.expire(LOGIN_USER_KEY+token, LOGIN_USER_TTL, TimeUnit.SECONDS);// 返回tokenSystem.out.println(token);return Result.ok(token);}

2.校验登录状态代码

 这段功能基于拦截器实现。考虑到用户的任何请求都可以刷新token的有效期,如下图所示,这部分由两个拦截器组成,第一个拦截器拦截所有请求,但都会放行,唯一的作用的token存在,刷新其在Redis中的有效期。第二个拦截没有token的请求。
在这里插入图片描述

  • 拦截器配置
@Configuration
public class MvcConfig implements WebMvcConfigurer {@ResourceStringRedisTemplate stringRedisTemplate;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new RefreshTokenInterceptor(stringRedisTemplate)).addPathPatterns("/**").order(0);registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/**").excludePathPatterns("/user/code","/user/login","/user/logout","/shop/**","/voucher/**","/shop-type/**","/upload/**","/blog/hot").order(1);}
}
  • 第一个拦截器
public class RefreshTokenInterceptor implements HandlerInterceptor {// 没有注册为Bean,只能手动引入private StringRedisTemplate stringRedisTemplate;public RefreshTokenInterceptor(StringRedisTemplate redisTemplate) {this.stringRedisTemplate = redisTemplate;}@Overridepublic boolean preHandle(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Object handler) throws Exception {// 1. 获取请求头的tokenString token = request.getHeader("authorization");if (StrUtil.isBlank(token)) {return true;}// 2. 基于token获取用户Map<Object, Object> userMap = stringRedisTemplate.opsForHash().entries(RedisConstants.LOGIN_USER_KEY + token);// 3. 用户是否存在if(userMap.isEmpty()){// 4. 放行return true;}// 5. 转为UserDTOUserDTO userDTO = BeanUtil.fillBeanWithMap(userMap, new UserDTO(), false);// 6. 保存用户信息到ThreadLocalUserHolder.saveUser(userDTO);// 刷新有效期stringRedisTemplate.expire(RedisConstants.LOGIN_USER_KEY+token, RedisConstants.LOGIN_USER_TTL, TimeUnit.MINUTES);// 7. 放行return true;}@Overridepublic void afterCompletion(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Object handler, Exception ex) throws Exception {// 4. 清理资源UserHolder.removeUser();}
}
  • 第二个拦截器
public class LoginInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Object handler) throws Exception {// 1. 拦截if(UserHolder.getUser() == null){response.setStatus(401);return false;}// 7. 已登录,放行return true;}@Overridepublic void afterCompletion(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Object handler, Exception ex) throws Exception {// 4. 清理资源UserHolder.removeUser();}
}
  • 其中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();}
}

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

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

相关文章

Java 常用容器及其遍历方式

目录 一、List接口1. 常见实现①ArrayList②LinkedList③Vector 2. 相关方法①共同的方法②ArrayList 和 Vector 独有的方法③LinkedList 独有的方法 二、Queue接口及Deque接口1. 常见实现①LinkedList②ArrayDeque③PriorityQueue 2. 相关方法①LinkedList②ArrayDeque③Prior…

鸿蒙Harmony应用开发—ArkTS声明式开发(基础手势:Select)

提供下拉选择菜单&#xff0c;可以让用户在多个选项之间选择。 说明&#xff1a; 该组件从API Version 8开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 子组件 无 接口 Select(options: Array<SelectOption>) 参数&#xff1a;…

Jmeter+Ant 接口自动化环境配置指南

一 、Jmeter安装与配置 https://blog.csdn.net/tester_sc/article/details/80746405 注&#xff1a;Jmeter5.0的环境变量配置与4.0或历往老版本有部分小差异&#xff0c;笔者用的Jmeter 5.0 二 、Ant的安装与配置 # Ant下载地址(下载到指定目录后&#xff0c;进行解压到当前…

Linux(centos)环境下安装Nginx的步骤文档

在Linux环境下安装Nginx是一个相对直接的过程&#xff0c;本篇文章将提供一个较为通用的安装指南&#xff0c;以及一些可能遇到的问题和解决方案。 目录 一、简介 二、先决条件 三、安装Nginx 1、使用包管理器安装 2、从源代码安装 四、验证安装 五、基本配置 六、常见…

NCP1271D65R2G中文资料规格书PDF数据手册引脚图参数图片价格功能特性描述

产品描述&#xff1a; NCP1271 是成功的 7 引脚电流模式 NCP12XX 系列的新一代引脚-引脚兼容新产品。该控制器通过使用可调节 Soft Skip 模式和集成的高电压启动 FET&#xff0c;实现了卓越的待机功耗。此专属 Soft Skip 还大大降低了噪音的风险。 因此可以在箝位网络中使用不…

Hello,Spider!入门第一个爬虫程序

在各大编程语言中&#xff0c;初学者要学会编写的第一个简单程序一般就是“Hello, World!”&#xff0c;即通过程序来在屏幕上输出一行“Hello, World!”这样的文字&#xff0c;在Python中&#xff0c;只需一行代码就可以做到。我们把这第一个爬虫就称之为“HelloSpider”&…

职场中的职业素养与成功之路

在职场中&#xff0c;职业素养是衡量一个人成功与否的重要标准。一个人的职业素养不仅影响个人发展&#xff0c;还关系到整个团队和组织的效益。本文将探讨职场中职业素养的重要性以及如何提升自身的职业素养&#xff0c;从而在职场中取得成功。 一、职业素养的重要性 1. 形象塑…

智慧公厕建设,助力打造宜居、韧性、可持续的智慧城市

公共厕所作为智慧城市的重要组成部分&#xff0c;对于城市的高质量发展起着至关重要的作用。智慧公厕建设旨在通过全面监测、控制和管理公共厕所&#xff0c;实现多方面功能&#xff0c;包括公共厕所环境监测与调控、厕位占用监测与引导、消耗品监测与缺失提示、安全防范与管理…

ElementUI Message 消息提示,多个显示被覆盖的问题

现象截图&#xff1a; 代码&#xff1a;主要是在this.$message 方法外层加上 setTimeout 方法 <script> export default {name: "HelloWorld",props: {msg: String,},methods: {showMessage() {for (let i 0; i < 10; i) {setTimeout(() > {this.$mess…

ThingsBoard Edge 设备控制

文章目录 一、RPC 功能1.服务端 RPC2.客户端 RPC3.MQTT RPC API3.1.服务端RPC3.2.客户端RPC 二、设备控制1.环境准备2.创建设备3.服务端PRC3.1.RPC消息主题3.2.程序源码3.3.创建仪表板3.4.边缘分配仪表板3.5.测试 4.客户端RPC4.1.RPC消息主题4.2.程序源码4.3.规则链4.4.测试 Th…

【析】一类动态车辆路径问题模型和两阶段算法

一类动态车辆路径问题模型和两阶段算法 摘要 针对一类动态车辆路径问题&#xff0c;分析4种主要类型动态信息对传统车辆路径问题的本质影响&#xff0c;将动态车辆路径问题(Dynamic Vehicle Routing Problem, DVRP)转化为多个静态的多车型开放式车辆路径问题(The Fleet Size a…

基于YOLOv8/YOLOv7/YOLOv6/YOLOv5的水下目标检测系统(深度学习模型+UI界面+训练数据集)

摘要&#xff1a;本研究详述了一种采用深度学习技术的水下目标检测系统&#xff0c;该系统集成了最新的YOLOv8算法&#xff0c;并与YOLOv7、YOLOv6、YOLOv5等早期算法进行了性能评估对比。该系统能够在各种媒介——包括图像、视频文件、实时视频流及批量文件中——准确地识别水…