短信登录,还能这样玩?

我们项目开发中比较通用的登录方式是用账号密码登录,但实际生活中短信登录的方式是大家所常用的。

今天分享一篇文章,文章内详细介绍利用 Session 实现短信登录的方法,大家可以把这个功能添加到自己的项目里,面试更加分!

下面的文章,前三步我先进行了短信登录的实现,最后一步对其进行了异常处理封装的细节优化。

实现验证码登录流程分析

1)发送验证码

用户在提交手机号后,会校验手机号是否合法,如果不合法,则要求用户重新输入手机号。

如果手机号合法,后台此时生成对应的验证码,同时将验证码进行保存,然后再通过短信的方式将验证码发送给用户。

2)短信验证码登录、注册

用户需输入收到的验证码及关联的手机号码。服务器后台会从当前的Session中提取先前存储的验证码,并与用户所输入的进行比对。若两者不匹配,用户将无法完成验证过程。若验证码相符,系统将依据用户输入的手机号码在数据库中进行用户查询。若查询结果显示该手机号尚未注册,系统将自动创建新的用户账户,并将基础信息存入数据库。无论用户是已存在或是新注册,系统都会更新 Session 信息,保存用户的登录凭证,以便用户能够顺利进行后续操作并随时访问其账户信息。

代码实现验证码发送

这里我使用 MyBatisX 实现项目的初始化。

1)正则表达式类

使用正则表达式分别对手机号、密码、验证码进行校验。

正则表达式可以去网上找,我这里提供下我的实现方式,可以作为参考。

public class RegexPatterns {
    /**
     * 手机号正则
     */
    public static final String PHONE_REGEX="1\\d{10}";
    /**
     * 邮箱正则
     */
    public static final String EMAIL_REGEX="/^([a-z0-9_\\.-]+)@([\\da-z\\.-]+)\\.([a-z\\.]{2,6})$/";
    /**
     * 验证码正则
     */
    public static final String VERIFY_CODE_REGEX="^[a-zA-Z\\d]{6}$";

}
2)正则校验工具类

对 Controller 层传入的手机号进行校验。

满足手机号正则表达式,手机号 11 位,并且只能为数字,才能校验通过

这里我使用的是 Hutool 工具类来校验手机号和验证码是否合法。

我贴一下 Hutool 的官网,有需要更加深层次了解的小伙伴可以访问下哦!

Hutool 官网:https://doc.hutool.cn/pages/index/

public class RegexUtils {

    /**
     * 校验手机号是否合法
     * @param phone
     * @return
     */
    public static boolean isPhoneInvalid(String phone){
        boolean matches = phone.matches(RegexPatterns.PHONE_REGEX);
        return matches;
    }

    /**
     * 校验验证码是否合法
     * @param code
     * @return
     */
    public boolean isCodeInvalid(String code){
        boolean matches = code.matches(RegexPatterns.VERIFY_CODE_REGEX);
        return matches;
    }
}
3)Controller 层
@GetMapping("/code")
    public boolean SendCode(String phone, HttpSession session){
        boolean b = userService.sendCode(phone, session);
        return b;
    }
4)Service 层

首先,系统会将用户输入的手机号通过正则表达式校验工具类进行验证,确保其格式正确无误。一旦手机号通过校验,程序便会自动生成一个随机验证码,并将其安全地存储在服务器的 Session 中。为了便于开发者实时监控验证码的生成和发送状态,系统特别设计了在控制台以 debug 模式输出验证码的功能,从而确保了整个验证流程的透明度和可追踪性。

@Resource
private UserService userService;

public boolean sendCode(String phone, HttpSession session) {
    //1、校验手机号是否合法
    if (!RegexUtils.isPhoneInvalid(phone)) {
        return false;
    }
    //2、生成随机验证吗
    String code = RandomUtil.randomNumbers(6);
    //3、保存验证码
    session.setAttribute("code",code);
    //4、打印日志
    log.debug("发送短信验证码成功,验证码:{}",code);
    return true;
}

注意:这里需要开启 debug 日志

controller 层中加入@Slf4j注解

logging:
  level:
    com.example: debug
# 开启debug日志

结果:

图片

实现验证码登录注册

短信验证登录注册逻辑:

1、校验手机号

2、校验验证码(取出 Session 中保存的验证码与表单中的输入的验证码吗进行比较)

3、不一致:报错

4、一致:根据手机号查询用户

5、判断用户是否存在

6、不存在,根据手机号创建新用户并保存

  • 用户是凭空创建的,所以密码可以没有,

  • 用户呢称和头像都是随机默认的

7、保存用户信息到 Session 中

1)Controller 层

我们登录需要获取两个参数,用户名和手机号,根据手机号来创建用户名。

@PostMapping("/login")
    public boolean login(LoginFormDTO loginFormDTO, HttpSession session){
        boolean login = userService.Login(loginFormDTO, session);
        return login;
    }

为了使代码更加美观,创建一个参数封装类。

/**
 * 用户登录请求参数封装类
 */
@Data
public class LoginFormDTO {
    private String code;
    private String phone;
}
2)Servcie 层
  /**
     * 用户登录
     * @param loginFormDTO
     * @param session
     * @return
     */
    @Override
    public boolean Login(LoginFormDTO loginFormDTO, HttpSession session) {
        //1、首先校验手机号和验证码是否合法
        String phone = loginFormDTO.getPhone();
        if(!RegexUtils.isPhoneInvalid(phone)){
            return false;
        }
        //2、校验验证码
        Object cachecode = session.getAttribute("code");
        String dtoCode = loginFormDTO.getCode();
        if (dtoCode==null&&!dtoCode.equals(cachecode)) {
            return false;
        }
        //3、根据手机号查询用户信息
        QueryWrapper<User> queryWrapper=new QueryWrapper<User>();
        queryWrapper.eq("phone", phone);
        //4、根据查询条件查询数据库中满足以上条件的用户
        User user = userMapper.selectOne(queryWrapper);
        if (user==null) {
            //创建用户
            user=CreateUser(phone);
        }
        //5、保存用户信息到session中
        session.setAttribute("user",user);
        return true;
    }

将创建用户的这段代码单独封装为一个函数。

    /**
     * 创建用户
     * @param phone
     * @return
     */
    private User CreateUser(String phone){
        User user = new User();
        user.setPhone(phone);
        user.setNickName(RandomUtil.randomString(10));
        //保存用户
        save(user);
        return user;
    }

发送验证码

get  http://localhost:8080/api/user/code?phone=13177576913

校验验证码并登录

post http://localhost:8080/api/user/login?phone=13177576913
&code=686422

运行结果:

图片

优化:全局通用返回对象

前面我的测试前端返回的数据都太过单调,因为这是一个功能的实现,并不是做一个完整的项目,但这样看起来确实不太美观。

所以这里使用 ==》全局统一 API 响应框架 ==》对整个接口进行统一的异常处理封装,这样就不需要写那么多的异常处理类了。

1)引入依赖

使用rest-api-spring-boot-starter这个依赖,不用打开 Redis ,但这个依赖需要加上。

<!--RestfulAPI-->
<dependency>
    <groupId>cn.soboys</groupId>
    <artifactId>rest-api-spring-boot-starter</artifactId>
    <version>1.3.0</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2)注解

启动类上加上这个@EnableRestFullApi 注解。

只需要引入依赖和加上注解这两步,Log 日志就变得与上面没优化前的不一样了。

图片

注意:这里的端口号是 8000,也就是说使用这个依赖必须要 8000 端口,我们在配置文件中所设置的 Web 端口没有用了,无法自定义端口

运行后,通过 Postman 测试,测试结果如下图所示:

3)用户信息脱敏

我们这里进行用户脱敏,将返回对象单独封装。

@Data
public class UserDTO {
    private Long id;
    private String nickName;
    private String icon;
}

修改登录login方法中的下面所示内容。

/**
     * copyProperties:属性拷贝——把user中的属性字动拷贝到UserDTO中
     * BeanUtils:使用的是包cn.hutool.core.bean下的工具类
     */
//5、保存用户信息到session中
UserDTO userDTO = BeanUtil.copyProperties(user, UserDTO.class);
session.setAttribute("user", userDTO);

最终,如下图所示成功返回三个信息。

以上,就是今天的分享,希望对大家有帮助。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

安卓刷机fastboot分段传输

win10 fastboot 无法识别&#xff0c;驱动下载地址GitHub - xushuan/google_latest_usb_driver_windows 把inf文件更新到设备管理器驱动更新即可 问题 archive does not contain super_empty.img Sending vbmeta_a (4 KB) OKAY [ 0.117s] Writing …

写了10000字:全面学习RocketMQ中间件

消息中间件是Java 项目开发中的重要组件,网络上对消息中间件的介绍很杂,V 哥今天要分享的干货共计10000+字,建议收藏起来,慢慢咀嚼享用。 通常我们知道的消息中间件有四种,我们来看一下这四种的特性: 但在分布式应用中,RocketMQ无疑是上镜率比较高的,我们知道 kafka是…

1572. 【基础赛】涂色(paint)

1572. 【基础赛】涂色&#xff08;paint&#xff09; (Input: paint.in, Output: paint.out) 时间限制: 2 s 空间限制: 256 MB 具体限制 题目描述 Introl获得了一个N行的杨辉三角&#xff0c;他将每行中值为奇数的位置涂为了黑色。 Chihiro将提出M次询问&#xff0c;在第L…

【SpringBoot】SpringBoot项目快速搭建

本文将介绍Springboot项目的快速搭建 快速创建SpringBoot项目 打开IDEA在File->New->Project中新建项目 点击左侧的Spring Initializr 输入以下信息&#xff1a; Name 项目名称Group 根据公司域名来&#xff0c;或者默认com.example【倒序域名】Package Name 包名&am…

只需几十秒即可在linux环境下部署一个完整的mysql服务【自动化部署脚本】

&#x1f341;博主简介&#xff1a; &#x1f3c5;云计算领域优质创作者 &#x1f3c5;2022年CSDN新星计划python赛道第一名 &#x1f3c5;2022年CSDN原力计划优质作者 &#x1f3c5;阿里云ACE认证高级工程师 &#x1f3c5;阿里云开发者社区专…

植物大战僵尸Python版,附带源码注解

目录 一、实现功能 二、安装环境要求 三、如何开始游戏 四、怎么玩 五、演示 六、部分源码注释 6.1main.py 6.2map.py 6.3Menubar.py 七、自定义 7.1plant.json 7.2zombie.json 一、实现功能 实施植物&#xff1a;向日葵、豌豆射手、壁桃、雪豆射手、樱桃炸弹、三…

Oracle体系结构:聊聊session与process

提前声明&#xff1a;本篇文章讨论的是专用服务器模式下的session和process&#xff1b;不讨论共享服务器模式&#xff0c;因为共享服务器现在真的应用的很少了&#xff0c;独占才是主流。共享服务器往往都是用在资源紧张的场合 &#xff0c;而且独占服务器模式有独立的PGA&…

stable-diffusion-webui怎么样增加自己训练的LoRA模型?

不怕笑话,我曾经为了找这个功能,居然搞了半天时间,结果还没有搞定。 后来再不断地研究各种教程,就是没有发现这个功能,无意间发现有一个人贴了一张图片, 他只是介绍放到这个目录,他没有告诉我这个目录怎么样来的,因为我在同样的位置上没有这个目录。 这样我训练出来…

探究 ChatGPT 的心脏--Transformer(基础知识第一篇)

Transformer 是 ChatGPT 的核心部分&#xff0c;如果将 AI 看做一辆高速运转的汽车&#xff0c;那么 Transformer 就是最重要的引擎。它是谷歌于 2017 年发表的《Attention is All You Need》中提出的 Sequence-to-sequence 的模型&#xff0c;诞生之后便一统江湖&#xff0c;在…

Flutter学习11 - Future 与 FutureBuilder

1、Future 可以利用 Future 实现异步调用 1.1、Future 的两种形式 自定义一个结果类 class Response {String _data;Response(this._data); }自定义方法实现 Future Future<Response> testFuture() {var random Random();int randomNumber random.nextInt(10);if …

DHCP抓包分析

DHCP动态路由配置协议&#xff0c;是C/S架构&#xff0c;由DHCP服务器为客户端动态分配IP信息。 DHCP客户端首次接入网络数据交互过程&#xff1a; 如何解决IP地址的冲突&#xff1a; ▫ DHCP服务器端&#xff1a;收到DHCP DISCOVER报文时&#xff0c;给客户端分配IP地址前会发…

智能运维场景 | 科技风险预警,能实现到什么程度?

[ 原作者&#xff1a;擎创夏洛克&#xff0c;本文略做了节选和改编 ] 每次一说到“风险预警”&#xff0c;就会有客户问我们能做怎样的风险预警。实际上在智能运维厂商来说&#xff0c;此风险非彼风险&#xff0c;不是能做银行的业务上的风险预警&#xff08;比如贷款风险等&a…

自动化测试框架 Selenium(3)

目录 1.前言 2.等待方式 2.1死等 2.2智能等待 3.游览器操作 3.1游览器最大化 3.2设置游览器的宽 高 3.3 游览器的前进和后退 3.4游览器滚动条 1.前言 本篇博客,我们将继续Selenium自动化测试的学习.在前面的章节中,俺介绍了Selenium是怎么回事,和键盘鼠标操作.还有url和…

2024年第十七届 认证杯 网络挑战赛 (A题)| 保暖纤维的保暖能力 |数学建模完整代码+建模过程全解全析

当大家面临着复杂的数学建模问题时&#xff0c;你是否曾经感到茫然无措&#xff1f;作为2022年美国大学生数学建模比赛的O奖得主&#xff0c;我为大家提供了一套优秀的解题思路&#xff0c;让你轻松应对各种难题。 让我们来看看认证杯 网络挑战赛 (A题&#xff09;&#xff01…

ruoyi-nbcio-plus基于vue3的flowable的支持自定义业务流程处理页面detail.vue的升级修改

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 http://122.227.135.243:9666/ 更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码&#xff1a…

Qt | 信号与槽 原理、连接、断开(面试无忧)

1、信号和槽是用于对象之间的通信的,这是 Qt 的核心。为此 Qt 引入了一些关键字,他们是slots、signals、emit,这些都不是 C++关键字,是 Qt 特有的,这些关键字会被 Qt 的 moc转换为标准的 C++语句。 2、Qt 的部件类中有一些已经定义好了的信号和槽,通常的作法是子类化部件…

2023年上半年信息系统项目管理师——综合知识真题与答案解释(1)

2023年上半年信息系统项目管理师 ——综合知识真题与答案解释(1) 零、00时光宝盒 1009 Rejections 1009 拒绝 Once, there was an old man, who was broke, living in a tiny house and owned a beat-up car. 有一次&#xff0c;有一个老人&#xff0c;他破产了&#…

谷歌google浏览器无法更新Chrome至最新版本怎么办?浏览器Chrome无法更新至最新版本

打开谷歌google浏览器提示&#xff1a;无法更新Chrome&#xff0c;Chrome无法更新至最新版本&#xff0c;因此您未能获得最新的功能和安全修复程序。点击「重新安装Chrome」后无法访问此网站&#xff0c;造成谷歌浏览器每天提示却无法更新Chrome至最新版本。 谷歌google浏览器无…

Netty源码解析-服务启动过程

文章目录 前言简单Netty服务器启动代码示例主线NioEventLoopGroup初始化关键代码 前言 Netty是一个高性能、异步事件驱动的网络应用框架&#xff0c;用于快速开发可维护的高性能协议服务器和客户端。它的服务启动过程涉及多个组件和步骤&#xff0c;下面我将对Netty的服务启动…

OpenAI推出GPTBot网络爬虫:提升AI模型同时引发道德法律争议

文章目录 一、GPTBot 简介二、功能特点三、技术细节3.1、用户代理标识3.2、数据采集规则3.3、数据使用目的3.4、网站屏蔽方法3.5、数据过滤 四、GPTBot 的道德和法律问题五、GPTBot 的使用方法和限制六、总结 一、GPTBot 简介 OpenAI 推出的网络爬虫GPTBot旨在通过从互联网上收…