Redis代替session 实现登录流程
Redis代替session 实现登录流程
如果使用String,他的value,用多占用一点空间,如果使用哈希,则他的value中只会存储他数据本身,如果不是特别在意内存,其实使用String就可以
设计key的具体细节
在设计这个key的时候,我们之前讲过需要满足两点
- key要具有唯一性
- key要方便携带
如果我们采用phone:手机号这个的数据来存储当然是可以的,但是如果把这样的敏感数据存储到redis中并且从页面中带过来毕竟不太合适,所以我们在后台生成一个随机串token,然后让前端带来这个token就能完成我们的整体逻辑了
整体访问流程
当注册完成后,用户去登录会去校验用户提交的手机号和验证码,是否一致,如果一致,则根据手机号查询用户信息,不存在则新建,最后将用户数据保存到redis,并且生成token作为redis的key,当我们校验用户是否登录时,会去携带着token进行访问,从redis中取出token对应的value,判断是否存在这个数据,如果没有则拦截,如果存在则将其保存到threadLocal中,并且放行。
基于Redis实现短信登录
UserServiceImpl代码
// public static final String LOGIN_CODE_KEY = "login:code:";
@Override
public Result login(LoginFormDTO loginForm, HttpSession session) {// 1.校验手机号String phone = loginForm.getPhone();if (RegexUtils.isPhoneInvalid(phone)) {// 2.如果不符合,返回错误信息return Result.fail("手机号格式错误!");}// 3.从redis获取验证码并校验String cacheCode = stringRedisTemplate.opsForValue().get(LOGIN_CODE_KEY + phone);String code = loginForm.getCode();if (cacheCode == null || !cacheCode.equals(code)) {// 不一致,报错return Result.fail("验证码错误");}// 4.一致,根据手机号查询用户 select * from tb_user where phone = ?User user = query().eq("phone", phone).one();// 5.判断用户是否存在if (user == null) {// 6.不存在,创建新用户并保存user = createUserWithPhone(phone);}// 7.保存用户信息到 redis中// 7.1.随机生成token,作为登录令牌String token = UUID.randomUUID().toString(true);// 7.2.将User对象转为HashMap存储UserDTO userDTO = BeanUtil.copyProperties(user, UserDTO.class);Map<String, Object> userMap = BeanUtil.beanToMap(userDTO, new HashMap<>(),CopyOptions.create().setIgnoreNullValue(true).setFieldValueEditor((fieldName, fieldValue) -> fieldValue.toString()));// 7.3.存储String tokenKey = LOGIN_USER_KEY + token;stringRedisTemplate.opsForHash().putAll(tokenKey, userMap);// 7.4.设置token有效期stringRedisTemplate.expire(tokenKey, LOGIN_USER_TTL, TimeUnit.MINUTES);// 8.返回tokenreturn Result.ok(token);
}
解决状态登录刷新问题
在这个方案中,他确实可以使用对应路径的拦截,同时刷新登录token令牌的存活时间,但是现在这个拦截器他只是拦截需要被拦截的路径,假设当前用户访问了一些不需要拦截的路径,那么这个拦截器就不会生效,所以此时令牌刷新的动作实际上就不会执行,所以这个方案他是存在问题的
既然之前的拦截器无法对不需要拦截的路径生效,那么我们可以添加一个拦截器,在第一个拦截器中拦截所有的路径,把第二个拦截器做的事情放入到第一个拦截器中,同时刷新令牌,因为第一个拦截器有了threadLocal的数据,所以此时第二个拦截器只需要判断拦截器中的user对象是否存在即可,完成整体刷新功能。
RefreshTokenInterceptor
public class RefreshTokenInterceptor implements HandlerInterceptor {private StringRedisTemplate stringRedisTemplate;public RefreshTokenInterceptor(StringRedisTemplate stringRedisTemplate) {this.stringRedisTemplate = stringRedisTemplate;}@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 1.获取请求头中的tokenString token = request.getHeader("authorization");if (StrUtil.isBlank(token)) {return true;}// 2.基于TOKEN获取redis中的用户String key = LOGIN_USER_KEY + token;Map<Object, Object> userMap = stringRedisTemplate.opsForHash().entries(key);// 3.判断用户是否存在if (userMap.isEmpty()) {return true;}// 5.将查询到的hash数据转为UserDTOUserDTO userDTO = BeanUtil.fillBeanWithMap(userMap, new UserDTO(), false);// 6.存在,保存用户信息到 ThreadLocalUserHolder.saveUser(userDTO);// 7.刷新token有效期stringRedisTemplate.expire(key, LOGIN_USER_TTL, TimeUnit.MINUTES);// 8.放行return true;}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {// 移除用户UserHolder.removeUser();}
}
LoginInterceptor
public class LoginInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 1.判断是否需要拦截(ThreadLocal中是否有用户)if (UserHolder.getUser() == null) {// 没有,需要拦截,设置状态码response.setStatus(401);// 拦截return false;}// 有用户,则放行return true;}
}
相关文章:
Redis代替session 实现登录流程
Redis代替session 实现登录流程 如果使用String,他的value,用多占用一点空间,如果使用哈希,则他的value中只会存储他数据本身,如果不是特别在意内存,其实使用String就可以 设计key的具体细节 在设计这个k…...
理解C++强制类型转换
理解C强制类型转换 文章目录 理解C强制类型转换理解C强制转换运算符1 static_cast1.1. static_cast用于内置数据类型之间的转换1.2 用于指针之间的转换 1.3 用于基类与派生类之间的转换2. const_cast2.1示例12.2 示例2——this指针 3.reinterpret_cast4.dynamic_cast C认为C风格…...
《TCP/IP网络编程》代码实现
文章目录 1. 项目说明1.1 项目特点2. 文件说明2.1 脚本文件2.1.1 `TCP_IP.sln`2.1.2 `xmake.lua`2.1.2.1 编译说明2.1.2.2 运行说明2.1.3 章节说明项目代码已经开源在github上! 微信公众号文章同步发表! 1. 项目说明 根据《TCP/IP网络编程》书籍学习,对其中的代码进行整理,…...
【Python】如何使用PyInstaller打包自己写好的代码
使用PyInstaller打包自己写好的代码 零、需求 最近接到一个小单,需要批量修改文档内容,用Python做好后要打包成exe程序给客户的Win7电脑使用,此时需要用到PyInstaller打包自己的代码,想到还要有给用户试用的需求,所以…...
Java 线程的调度与时间片
🙈作者简介:练习时长两年半的Java up主 🙉个人主页:程序员老茶 🙊 ps:点赞👍是免费的,却可以让写博客的作者开兴好久好久😎 📚系列专栏:Java全栈,…...
Java项目-文件搜索工具
目录 项目背景 项目效果 SQLite的下载安装 使用JDBC操作SQLite 第三方库pinyin4j pinyin4j的具体使用 封装pinyin4j 数据库的设计 创建实体类 实现DBUtil 封装FileDao 设计scan方法 多线程扫描 周期性扫描 控制台版本的客户端 图形化界面 设计图形化界面 项目…...
记录开发中遇到关于MySQL的一些问题-MySQL版
本篇文章是记录开发中遇到关于MySQL的一些问题: 希望在这篇文章也能够找到你正在查找的问题,解决问题 Good Luck ! 关于Id 的一些问题 数据库并没有直接写SQL,是通过使用IDEA 同一个公司下的数据库软件生成的(DataGrip…...
2023-10-06 LeetCode每日一题(买卖股票的最佳时机含手续费)
2023-10-06每日一题 一、题目编号 714. 买卖股票的最佳时机含手续费二、题目链接 点击跳转到题目位置 三、题目描述 给定一个整数数组 prices,其中 prices[i]表示第 i 天的股票价格 ;整数 fee 代表了交易股票的手续费用。 你可以无限次地完成交易&…...
openGauss学习笔记-91 openGauss 数据库管理-内存优化表MOT管理-内存表特性-使用MOT-MOT使用MOT外部支持工具
文章目录 openGauss学习笔记-91 openGauss 数据库管理-内存优化表MOT管理-内存表特性-使用MOT-MOT使用MOT外部支持工具91.1 gs_ctl(全量和增量)91.2 gs_basebackup91.3 gs_dump91.4 gs_restore openGauss学习笔记-91 openGauss 数据库管理-内存优化表MOT…...
PostgreSQL快速入门
PostgreSQL快速入门:轻松掌握强大的开源数据库 PostgreSQL(简称Postgres)是一款强大、可定制且免费的开源关系型数据库管理系统(RDBMS)。它以其高级功能、可扩展性和安全性而著称,被广泛用于各种规模的项目…...
MATLAB:线性系统的建模与仿真(含完整程序)
目录 前言实验内容一、先看作业题目要求二、作业正文Modeling LTI systemsEstablish model1.tf(sys2)2. tf(sys3)3.zpk(sys1)4. zpk(sys3)5. ss(sys1)6. ss(sys2)7.[num,den] tfdata(sys1)8.[num,den] tfdata(sys2)9.[num,den] tfdata(sys3)10.[num,den] tfdata(sys1,’v’…...
mycat实现mysql读写分离
架构图: 视频地址...
【C++】STL详解(十一)—— unordered_set、unordered_map的介绍及使用
📝个人主页:Sherry的成长之路 🏠学习社区:Sherry的成长之路(个人社区) 📖专栏链接:C学习 🎯长路漫漫浩浩,万事皆有期待 上一篇博客:【C】STL…...
【C语言】动态通讯录(超详细)
通讯录是一个可以很好锻炼我们对结构体的使用,加深对结构体的理解,在为以后学习数据结构打下结实的基础 这里我们想设计一个有添加联系人,删除联系人,查找联系人,修改联系人,展示联系人,排序这几…...
Mac下docker安装MySQL8.0.34
学习并记录一下如何用docker部署MySQL 在Docker中搜索并下载MySQL8.0.x的最新版本 下载好后,在Images中就可以看到MySQL的镜像了 通过下面的命令也可以查看docker images启动镜像,使用下面的命令就可以启动镜像了docker run -itd --name mysql8.0.34 -…...
基于python编写的excel表格数据标记的exe文件
目录 一、需求: 二、思路: 三、工具 四、设计过程 (一)根据需要导入相关的图形界面库 (二)创建图形窗口 (三)标签设计 (四)方法按钮设计 ࿰…...
acwing算法基础之基础算法--高精度加法算法
目录 1 知识点2 模板 1 知识点 大整数 大整数,它们的长度都为 1 0 6 10^6 106。大整数是指长度为 1 0 6 10^6 106的整数。 大整数 - 大整数 大整数 * 小整数 大整数 / 小整数 把大整数存储到向量中,需要考虑高位在前还是低位在前,低位在前…...
openGauss学习笔记-84 openGauss 数据库管理-内存优化表MOT管理-内存表特性-MOT部署服务器优化:x86
文章目录 openGauss学习笔记-84 openGauss 数据库管理-内存优化表MOT管理-内存表特性-MOT部署服务器优化:x8684.1 BIOS84.2 操作系统环境设置84.3 网络 openGauss学习笔记-84 openGauss 数据库管理-内存优化表MOT管理-内存表特性-MOT部署服务器优化:x86 …...
二分查找:34. 在排序数组中查找元素的第一个和最后一个位置
个人主页 : 个人主页 个人专栏 : 《数据结构》 《C语言》《C》《算法》 文章目录 前言一、题目解析二、解题思路1. 暴力查找2. 一次二分查找 部分遍历3. 两次二分查找分别查找左右端点1.查找区间左端点2. 查找区间右端点 三、代码实现总结 前言 本篇文…...
javaee ssm框架项目整合thymeleaf2.0 更多thymeleaf标签用法 项目结构图
创建ssmthymeleaf项目 创建ssmthymeleaf项目参考此文 thymeleaf更多常用标签 <!DOCTYPE html> <html lang"en" xmlns:th"http://www.thymeleaf.org"> <head><meta charset"UTF-8"><title>Title</title> …...
lv7 嵌入式开发-网络编程开发 11 TCP管理与UDP协议
目录 1 TCP管理 1.1 三次握手 1.2 四次挥手 1.3 保活计时器 2 wireshark安装及实验 3.1 icmp协议抓包演示 3.2 tcp协议抓包演示 3 UDP协议 3.1 UDP 的主要特点: 4 练习 1 TCP管理 1.1 三次握手 TCP 建立连接的过程叫做握手。 采用三报文握手࿱…...
overleaf在线编辑工具使用教程
文章目录 1 用 orcid注册overleaf获取模板2 使用模板 1 用 orcid注册overleaf获取模板 通常来说,在期刊投稿网站information for author中找template 。下载压缩包后上传到over leaf中。 加入找不到官方模板,用overleaf中的 2 使用模板 .bib文件&…...
Python基础复习【第一弹】【黑马】
本篇是观看b站黑马视频所做的笔记第一弹,为1-98节。 b站-黑马Python # 1.Hello World print("Hello World")# 2.字面量 在代码中,被写下来固定的值# 3.字符串 print("python")# 4.单行注释 # 多行注释""" "&q…...
【Word】公式编辑器中连字符/减号等显示偏长/过长
问题 当公式编辑器中出现连字符的时候,连字符显示偏长,如下图所示: 方法 在连字符的前后加上双引号后即可解决连字符显示偏长的问题。 最终效果对比如下: 结语 Word的公式编辑器中,双引号内部的内容被当做普通…...
架构设计系列4:如何设计高性能架构
在架构设计系列1:什么是架构设计中,我们讲了架构设计的主要目的,是为了解决软件系统复杂度带来的问题,今天我们来聊聊软件系统复杂度的来源之一高性能。 一、什么是高性能架构? 要搞清楚什么是高性能架构,…...
1392. 最长快乐前缀
链接: 1392. 最长快乐前缀 题解: class Solution { public:string longestPrefix(string s) {if (s.size() < 0) {return "";}int MOD 1e9 7;// 构建26的n次方,预处理std::vector<long> pow26(s.size());pow26[0] 1…...
【C++设计模式之备忘录模式:行为型】分析及示例
简介 备忘录模式(Memento Pattern)是一种行为型设计模式,它用于保存和恢复对象的状态。备忘录模式通过将对象的状态封装成一个备忘录(Memento),并将备忘录保存在一个管理者(Caretakerÿ…...
数据结构与算法(四):哈希表
参考引用 Hello 算法 Github:hello-algo 1. 哈希表 1.1 哈希表概述 哈希表(hash table),又称散列表,其通过建立键 key 与值 value 之间的映射,实现高效的元素查询 具体而言,向哈希表输入一个键…...
FFmpeg 命令:从入门到精通 | ffplay 播放控制选项
FFmpeg 命令:从入门到精通 | ffplay 播放控制选项 FFmpeg 命令:从入门到精通 | ffplay 播放控制选项选项表格图片 FFmpeg 命令:从入门到精通 | ffplay 播放控制选项 选项表格 项目说明Q,Esc退出播放F,鼠标左键双击全…...
代码随想录day59
647. 回文子串 给你一个字符串 s ,请你统计并返回这个字符串中 回文子串 的数目。 回文字符串 是正着读和倒过来读一样的字符串。 子字符串 是字符串中的由连续字符组成的一个序列。 具有不同开始位置或结束位置的子串,即使是由相同的字符组成&#…...
购物网站前台模板/seo标题关键词优化
内部表和外部表的区别: 删除外部表的时候只会删除表的元数据而HDFS上的数据不会被删除。 删除内部表的时候会删除表的元数据和HDFS上的数据。 外部表相对来说更安全些。 创建外部表的指令: create EXTERNAL table test2;(若不加EXTERNAL则默认创建的是内…...
网站建设教程学校/合肥seo代理商
编译的时候报警告:warning: assignment makes pointer from integer without a cast 出现这个警告的原因是在使用函数之前没有对函数进行声明,未经声明的函数原型一律默认为返回int值。 这样、就相当于你调用了返回值为int的函数,并将其赋给…...
dreamweaver最新版本/搜索引擎优化的方法有哪些
1. 作用 在项目中引入rem,可以解决多屏适配问题 2. 原因 vant插件中的默认样式都是使用px作为单位,所有移动端的项目就需要来用rem进行适配,方便各种屏幕大小的设备都可以正常的浏览 3. 解决 两个工具包 : posstcss-pxtorem &…...
海安企业网站建设/如何建立网上销售平台
1 java浮点型比较大小Float.parseFloat(String)和Float.valueOf(String).floatValue()的区别Float.parseFloat(String)表示 把String字符串转换成float原始类型的单精度数值,Float.parseFloat("")而Float.valueOf(String)是把String字符串转换成float的封装类Floa…...
ECS 安装wordpress/子域名查询工具
百万富翁问题—安全多方计算 是由图灵奖获得者姚期智提出的。 有A、B两个富翁,A资产i亿元,B资产j亿元,i、j均在0-10范围内,在互不让对方知道自己资产的情况下,比较A和B的资产谁多谁少。 那么如何去比较呢?…...
做爰全过程免费的视频 网站/百度经验
杂散发射与杂散干扰...