基于Redis实现登录

news2025/1/16 6:48:26

1.发送短信验证码

@Override
    public Result sendCode(String phone, HttpSession session) {
        //校验手机号
        if(RegexUtils.isPhoneInvalid(phone)){
            //如果不符合,返回错误信息。
            return Result.fail("手机号格式错误!");
        }

        //生成验证码
        String code = RandomUtil.randomNumbers(6);
        //保存验证码到redis
        stringRedisTemplate.opsForValue().set("login:code:"+phone,code,2, TimeUnit.MINUTES);

        //发送验证码
        log.debug("发送短信验证码成功,验证码:{}"+code);
        //返回ok
        return Result.ok();
    }

 生成的验证码需要保存到redis中,用于后面登录时的判断。

保存到redis中的数据类型选为String类型。

为了保证每个用户对应的验证码的唯一性,所以使用电话作为key.

2.登录、注册

public Result login(LoginFormDTO loginForm, HttpSession session) {
        //1.校验手机号
        String phone = loginForm.getPhone();
        if(RegexUtils.isPhoneInvalid(phone)){
            //如果不符合,返回错误信息。
            return Result.fail("手机号格式错误!");
        }
        //校验验证码
        String cacheCode = stringRedisTemplate.opsForValue().get("login:code:"+phone);
        String code = loginForm.getCode();
        if (cacheCode==null|| !cacheCode.equals(code)){
            //验证码不一致,报错
            return Result.fail("验证码错误!");
        }
        //一致,根据手机号查询用户
        User user = query().eq("phone", phone).one();
        //判断用户是否存在
        if (user==null){
            //用户不存在,创建新用户并保存。
            user = createUserWithPhone(phone);
        }
        //保存用户信息到redis
        //随机生成token,作为登录令牌
        String tokenKey = "login:user:" + UUID.randomUUID().toString(true);
        //将user对象转为Map存储
        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()));
        stringRedisTemplate.opsForHash().putAll(tokenKey,userMap);
        //设置有效期
        stringRedisTemplate.expire(tokenKey,30,TimeUnit.MINUTES);


        return Result.ok(tokenKey);
    }

这里会返回token给客户端,然后客户端每次请求都会携带这个token,用于后面的登录验证。(这里有点类似于JWT Token认证的意思了)

保存用户对象到redis中有两种方式:

1.采用String类型(通过序列化)

2.采用Hash类型

 

3.登录校验

 

注:

1.这里需要不断去刷新token的有效时间。

2.为什么需要把用户信息保存到ThreadLocal中?

   为了保证各个线程中数据的互不干扰,同时也要让controller也要拿到对应的用户信息。

//这个拦截器拦截所有请求
public class RefreshLoginInterceptor implements HandlerInterceptor {

    private StringRedisTemplate stringRedisTemplate;

    public RefreshLoginInterceptor(StringRedisTemplate stringRedisTemplate) {
        this.stringRedisTemplate = stringRedisTemplate;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //获取请求头中的token
        String token = request.getHeader("authorization");
        if (StrUtil.isBlank(token)){
            return true;
        }
        //基于TOKEN获取redis中的用户
        Map<Object, Object> userMap = stringRedisTemplate.opsForHash().entries(token);
        //判断用户是否存在
        if(userMap.isEmpty()){
            return true;
        }
        //将查询到的map数据转为UserDTO对象
        UserDTO userDTO = BeanUtil.fillBeanWithMap(userMap, new UserDTO(), false);

        //存在,保存用户信息到ThreadLocal
        UserHolder.saveUser(userDTO);

        //刷新token的有效期
        stringRedisTemplate.expire(token,30, TimeUnit.MINUTES);
        //放行
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
         //移除用户
        UserHolder.removeUser();
    }
}
//拦截部分请求,判断用户是否登录
public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //判断是否需要拦截(ThreadLocal中是否有用户)
        if (UserHolder.getUser() == null){
            //没有用户,表示没有登录
            response.setStatus(401);
            return false;
        }
        //放行
        return true;
    }

}
@Configuration
public class MvcConfig implements WebMvcConfigurer {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor())
                .excludePathPatterns(
                        "/shop/**",
                        "/shop-type/**",
                        "/upload/**",
                        "/voucher/**",
                        "/blog/hot",
                        "/user/code",
                        "/user/login"
                ).order(1);
        //"/**":表示拦截所有  order中数值表示优先级,值大表示优先级低。
        registry.addInterceptor(new RefreshLoginInterceptor(stringRedisTemplate)).addPathPatterns("/**").order(0);

    }
}

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

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

相关文章

Codeforces Round #699 (Div. 2) C. Fence Painting

翻译&#xff1a; You finally woke up after this crazy dream and decided to walk around to clear your head. Outside you saw your houses fence — so plain and boring, that youd like to repaint it. You have a fence consisting of &#x1d45b;n planks, where …

网络实验之VTP协议

一、VTP协议简介 VLAN中继协议&#xff0c;VTP&#xff0c;VLAN TRUNKING PROTOCOL&#xff0c;是CISCO专用协议&#xff0c;大多数交换机都支持该协议。VTP负责在VTP域内同步VLAN信息&#xff0c;这样就不必在每个交换上配置相同的VLAN信息。如协议名称&#xff0c;VTP协议需要…

“世界上最鸽派”的央行转鹰,透露了什么信号?

​当地时间周二&#xff0c;日本中央银行结束货币政策会议后宣布&#xff0c;部分调整当前超宽松货币政策&#xff0c;将长期利率波动幅度由正负0.25%扩展至正负0.5%。这一“黑天鹅”令全球投资者感到大为震惊。长期以来&#xff0c;投资者将日本央行看作是最后一家尚未放弃其长…

【Linux】---文件基础I/O(上)

文章目录回顾C语言文件操作接口文件相关的系统调用接口打开和关闭文件文件的打开方式文件描述符文件描述符的分配规则write、read重定向dup2mysell回顾C语言文件操作接口 在C语言中对于文件的操作有着几个常用的接口可以调用 fopen//打开文件 fclose//关闭文件 fprintf//输出…

L1-070 吃火锅(分数 15)

以上图片来自微信朋友圈&#xff1a;这种天气你有什么破事打电话给我基本没用。但是如果你说“吃火锅”&#xff0c;那就厉害了&#xff0c;我们的故事就开始了。 本题要求你实现一个程序&#xff0c;自动检查你朋友给你发来的信息里有没有 chi1 huo3 guo1。 输入格式&#x…

即时通讯音视频开发数字视频介绍

数字视频就是先用摄像机之类的视频捕捉设备&#xff0c;将外界影像的颜色和亮度信息转变为电信号&#xff0c;再记录到储存介质&#xff08;如录像带&#xff09;。 图像&#xff1a; 是人对视觉感知的物质再现。三维自然场景的对象包括&#xff1a;深度&#xff0c;纹理和亮度…

InnoDB详解2

文章目录InnoDB详解21 行格式1 Compact行格式详解1 变长字段长度列表&#xff08;两个字节&#xff09;2 NULL值列表&#xff08;1个字节&#xff09;3 记录头信息 &#xff08;重点&#xff09;2 Dynamic行格式2 页的上层结构InnoDB详解2 1 行格式 规定每条记录是怎么存储的…

汽车租赁服务小程序开发, 新时代下的行业商机

随着我国经济水平的提升&#xff0c;群众生活水平不断改善&#xff0c;人们的出行方式也发生了非常大的变化&#xff0c;不再依赖传统的出行方式&#xff0c;而是将目光转移到汽车上&#xff0c;作为当下便捷的出行方式之一&#xff0c;在面对远程旅游时却显得有些吃力&#xf…

React扩展:fragment、Context

目录 1.fragment fragment标签能包裹其它标签&#xff0c;但最后不会渲染到DOM树上。 import React, { Component, Fragment } from reactexport default class Demo extends Component {render() {return (<Fragment><input type"text" /><input …

Stealth-Persist混合内存系统中持久应用程序的体系结构支持

文章目录crash-consistent applications 崩溃一致性程序摘要一、引言二、背景A.新兴的非易失性存储器B.混合主存储器(HMM)C.页面缓存策略D. 目前的工业HMM系统E. 持久性内存编程模式F.动机三、设计A.设计要求B.设计选项C.Stealth-PersistD.概述E. Stealth-Persist NVM库的比较四…

如何用DWDM射频光纤技术实现200公里外的站点分集

本文概述了大型卫星和数据通信服务提供商如何通过使用DWDM射频光纤解决方案为Ka波段卫星数据传输实施经济高效的位置分集天线安装。 什么是DWDM技术? DWDM是Dense Wavelength Division Multiplexing的缩写&#xff0c;即密集波分复用技术&#xff0c;指的是一种光纤数据传输技…

pytest-需要模块相应的库

1. pytest-需要模块相应的库 文章地址&#xff1a;http://www.pythonck.com/archives/docs/1-2/13-2/13002-2 http://www.pythonck.com/archives/docs/1-2/13-2/13002-2 pytest-断言、跳过及运行 三元表达式&#xff1a;三元表达式又称三目运算符。在python中并没有三元表达式…

数商云SRM供应商系统打造家居建材企业完整电商数据生态平台

随着5G、物联网、大数据、人工智能、云计算等技术的快速发展&#xff0c;全球科技不断突破创新&#xff0c;推动了整个社会的智能化发展&#xff0c;同时&#xff0c;也带动了包含家居业在内的制造行业的技术创新、产品更迭以及更加精细化的经营管理。 数字经济时代&#xff0…

代替塞规的高精度孔径测量方法——泊肃叶压差法

摘要&#xff1a;针对现有压力衰减法孔径测量中存在的基本概念不清和实施方法不明确等问题&#xff0c;本文详细介绍了压力衰减法的孔径测量基本原理&#xff0c;并重点介绍压差法测量中的高精度压力控制方法&#xff0c;为各种微小孔径和等效孔径的准确测量提供切实可行的解决…

EOF的实际含义

在学习C语言的时候&#xff0c;遇到的一个问题就是EOF。 它是end of file的缩写&#xff0c;表示"文字流"&#xff08;stream&#xff09;的结尾。这里的"文字流"&#xff0c;可以是文件&#xff08;file&#xff09;&#xff0c;也可以是标准输入&#x…

Linux tracepoint 简介

文章目录前言一、跟踪点的目的二、跟踪点的使用2.1 简介2.2 DECLARE_TRACE三、TRACE_EVENT参考资料前言 本文提供了如何在内核中插入跟踪点并将 probe functions 连接到它们的示例&#xff0c;并提供了一些 probe functions 的示例。可以在不创建自定义内核模块的情况下使用跟…

高可用 Canal集群( 秒懂 + 史上最全)

文章很长&#xff0c;而且持续更新&#xff0c;建议收藏起来&#xff0c;慢慢读&#xff01;疯狂创客圈总目录 博客园版 为您奉上珍贵的学习资源 &#xff1a; 免费赠送 :《尼恩Java面试宝典》 持续更新 史上最全 面试必备 2000页 面试必备 大厂必备 涨薪必备 免费赠送 经典…

工控安全-Modbus协议

文章目录一、什么是Modbus协议二、Modbus通信过程三、Modbus存储区四、Modbus协议类型4.1 Modbus RTU协议4.1.1 Modbus报文帧结构4.1.2 主机对从机读数据操作4.1.3 主机对从机写数据操作4.1.4 10功能码数据解析4.1.5 总结4.2 Modbus ACSII协议4.3 Modbus-TCP4.4 Modbus-PLUS一、…

SecXOps 关键技术 模型更新

模型更新 定义内涵 本节的模型更新是指在模型训练完成并正式上线后&#xff0c;由运维人员采集并提供新的数据对 原有模型进行再训练、更新参数的过程。 技术背景 随着时间的推移&#xff0c;由于周期性事件、突变等状况的发生&#xff0c;当下的数据集和之前用于训练 模型…

Anaconda开发环境

Anaconda开发环境 Anacanda是一个基于数据分析和机器学习的集成环境&#xff08;给我们集成好了数据分析和机器学习对应的各种环境和模块&#xff09; jupyter&#xff1a;就是Anaconda这个集成环境提供的一个基于浏览器可视化的编码工具。 注意事项&#xff1a;在环境搭建的…