spring boot3登录开发-3(账密登录逻辑实现)

 

⛰️个人主页:     蒾酒

🔥系列专栏:《spring boot实战》

🌊山高路远,行路漫漫,终有归途。


目录

前置条件

内容简介

用户登录逻辑实现

创建交互对象

1.创建用户登录DTO

2.创建用户登录VO

创建自定义登录业务异常

1.创建验证码错误异常

2.创建用户不存在异常

3.创建密码错误异常

4.创建用户被封禁异常

2.登录业务逻辑实现

3.测试接口


前置条件

本文衔接上文,请从上文开始

spring boot3登录开发-2(1图形验证码接口实现)-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/qq_62262918/article/details/136064820?spm=1001.2014.3001.5502用户表设计如下:

create table user
(id           bigint auto_increment comment '主键'primary key,user_name    varchar(32)                            null comment '用户昵称',password     varchar(256)                           null comment '密码',user_account varchar(64)                            null comment '账号',user_role    varchar(256) default 'user'            null comment '用户角色:user / admin',avatar       varchar(1024)                          null comment '头像',create_time  datetime     default (now())           null comment '创建时间',update_time  datetime     default CURRENT_TIMESTAMP null comment '更新时间',is_delete    tinyint(1)   default 0                 null comment '逻辑删除:1删除/0存在',gender       tinyint(1)                             null comment '性别',status       tinyint(1)   default 1                 not null comment '状态:1正常0禁用'
)comment '用户表';INSERT INTO `user` VALUES (1,'蒾酒','e10adc3949ba59abbe56e057f20f883e','admin','admin',NULL,'2024-02-02 18:54:44','2024-02-02 18:54:44',0,NULL,1);

内容简介

 上文我们已经实现了图形验证码接口,本文我们实现登录逻辑

  • 通过用户登录DTO(数据传输对象)接收用户登录填写信息
  • 通过注解@NotNull、@Valid进行参数非空校验
  • 通过redis缓存的验证码信息与用户提交的比对验证
  • 通过全局异常处理处理参数为空、用户不存在、密码错误、验证码错误、用户被封禁等业务异常

用户登录逻辑实现

作者习惯于将业务代码全部放在service层里面,controller层只用于暴漏接口封装返回结果。

创建交互对象

1.创建用户登录DTO

说白了就是用户登录表单提交发起post请求,请求体负载的登录对象后端需要有个对象跟表单对象字段对应接收:请求体json->接收对象。这一过程也叫反序列化。

通过@NotNull做非空校验

import jakarta.validation.constraints.NotNull;
import lombok.Data;/*** @author mijiupro*/
@Data
public class UserLoginDTO {@NotNull(message = "账号不能为空")private String userAccount;//用户账号@NotNull(message = "密码不能为空")private String password;//密码@NotNull(message = "验证码id不能为空")private String captchaId;//验证码id@NotNull(message = "验证码内容不能为空")private String captcha;//验证码内容
}

2.创建用户登录VO

通俗来说就是用户登录成功后返回给前端一个合法令牌token,以及一些非敏感信息方便前端展示,这些信息包装成一个对象,展示对象->json。这一过程又叫序列化。

import lombok.Builder;
import lombok.Data;import java.io.Serializable;/*** @author mijiupro*/
@Data
@Builder
public class UserLoginVO implements Serializable {private String token;//令牌private String userName;//用户名private String avatar;//头像
}

创建自定义登录业务异常

说白了就是登录代码可能会判断账号是否存在密码是否正确,当账号不存在或密码错误需要返回对应提示信息,这种类似情况多了你的代码就会很多if-return,代码就会很难看;那么通过自定义异常去到异常处理的方法里面写对应返回提示以及其他逻辑,这样直接抛出对应异常AOP拦截到该异常走对应异常处理逻辑即可。(一句话概括就是:把处理特殊业务异常情况的代码逻辑抽取出来放到别的类里面写,可以使代码更加清晰和可维护​​​​​​​)

1.创建验证码错误异常

import com.mijiu.commom.enumerate.ResultEnum;
import lombok.Getter;/*** @author mijiupro*/
@Getter
public class CaptchaErrorException extends RuntimeException {private final ResultEnum resultEnum;//返回提示信息枚举(code,message)public CaptchaErrorException(ResultEnum resultEnum) {this.resultEnum = resultEnum;}
}

2.创建用户不存在异常

import com.mijiu.commom.enumerate.ResultEnum;
import lombok.Getter;/*** 账户不存在异常** @author mijiupro*/
@Getter
public class AccountNotFoundException extends RuntimeException {private final ResultEnum resultEnum;public AccountNotFoundException(ResultEnum resultEnum) {this.resultEnum = resultEnum;}
}

3.创建密码错误异常

import com.mijiu.commom.enumerate.ResultEnum;
import lombok.Getter;/*** 密码错误异常** @author mijiupro*/
@Getter
public class PasswordErrorException extends RuntimeException {private final ResultEnum resultEnum;public PasswordErrorException(ResultEnum resultEnum) {this.resultEnum = resultEnum;}}

4.创建用户被封禁异常

import com.mijiu.commom.enumerate.ResultEnum;
import lombok.Getter;/*** @author mijiupro*/
@Getter
public class AccountForbiddenException extends RuntimeException {private final ResultEnum resultEnum;public AccountForbiddenException(ResultEnum resultEnum) {this.resultEnum = resultEnum;}
}

2.登录业务逻辑实现

代码逻辑:参数校验(使用注解方式校验)----验证码校验----账号存在检验----密码校验----用户状态判断

import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.mijiu.commom.enumerate.ResultEnum;
import com.mijiu.commom.exception.AccountForbiddenException;
import com.mijiu.commom.exception.AccountNotFoundException;
import com.mijiu.commom.exception.CaptchaErrorException;
import com.mijiu.commom.exception.PasswordErrorException;
import com.mijiu.commom.model.dto.UserLoginDTO;
import com.mijiu.commom.model.vo.UserLoginVO;
import com.mijiu.commom.util.JwtUtils;
import com.mijiu.entity.User;
import com.mijiu.mapper.UserMapper;
import com.mijiu.service.UserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;import java.util.Map;/*** <p>* 用户表 服务实现类* </p>** @author 蒾酒* @since 2024-02-03*/
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {private final UserMapper userMapper;private final JwtUtils jwtUtils;private final StringRedisTemplate stringRedisTemplate;public UserServiceImpl(UserMapper userMapper, JwtUtils jwtUtils, StringRedisTemplate stringRedisTemplate) {this.userMapper = userMapper;this.jwtUtils = jwtUtils;this.stringRedisTemplate = stringRedisTemplate;}@Overridepublic UserLoginVO login(@Valid UserLoginDTO userLoginDTO) {// 获取验证码idString captchaId = userLoginDTO.getCaptchaId();// 获取用户提交验证码String userCaptcha = userLoginDTO.getCaptcha();// 获取缓存验证码String cacheCaptcha = stringRedisTemplate.opsForValue().get("login:captcha:" + captchaId);// 比较验证码是否正确if (cacheCaptcha == null || !cacheCaptcha.equalsIgnoreCase(userCaptcha)) {throw new CaptchaErrorException(ResultEnum.USER_CAPTCHA_ERROR);}// 判断用户是否存在User loginUser = new LambdaQueryChainWrapper<>(userMapper).select(User::getId, User::getUserAccount, User::getPassword,User::getUserName, User::getUserRole,User::getAvatar, User::getStatus).eq(User::getUserAccount, userLoginDTO.getUserAccount()).one();if (loginUser == null) {throw new AccountNotFoundException(ResultEnum.USER_NOT_EXIST);}log.info("loginUser: {}", loginUser);// 判断密码是否正确String md5Password = DigestUtils.md5DigestAsHex(userLoginDTO.getPassword().getBytes());if (!md5Password.equals(loginUser.getPassword())) {throw new PasswordErrorException(ResultEnum.USER_PASSWORD_ERROR);}// 判断用户状态是否正常if (!loginUser.getStatus()) {throw new AccountForbiddenException(ResultEnum.USER_ACCOUNT_FORBIDDEN);}// 生成tokenString token = jwtUtils.generateToken(Map.of("userId", loginUser.getId(),"userRole",loginUser.getUserRole()),"user");//构建响应对象return UserLoginVO.builder().userName(loginUser.getUserName()).avatar(loginUser.getAvatar()).token(token).build();}
}

这里要说一下的是通常数据库不放密码明文,这样做可以防止别人获取数据库直接得到账密登录违规操作风险,代码中使用MD5加密是很容易被暴力破解的所以可以用MD5加盐策略或者其他安全加密算法

3.测试接口

测试之前记得把图形验证码接口中redis缓存验证码的过期时间设置的长一点。

先生成一个验证码

日志打印图形验证码文本

正常测试

验证码错误测试

用户不存在测试

密码错误测试

账号被封禁测试

字段status修改为0代表被禁用

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

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

相关文章

unity ui界面优化

优化一个比较复杂的界面&#xff0c;里面有多个rt和组件。 在初次打开这个界面的时候会发生1s多的卡顿&#xff0c;还是非常严重的。 分析 通过profiler分析 1.打开界面时卡顿。 分析&#xff1a;除了update和dotween相关逻辑&#xff0c;主要在于打开时的lua function调用…

Day20_网络编程(软件结构,网络编程三要素,UDP网络编程,TCP网络编程)

文章目录 Day20 网络编程学习目标1 软件结构2 网络编程三要素2.1 IP地址和域名1、IP地址2、域名3、InetAddress类 2.2 端口号2.3 网络通信协议1、OSI参考模型和TCP/IP参考模型2、UDP协议3、TCP协议 2.4 Socket编程 3 UDP网络编程3.1 DatagramSocket和DatagramPacket1、Datagram…

【Java程序设计】【C00294】基于Springboot的车辆充电桩管理系统(有论文)

基于Springboot的车辆充电桩管理系统&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的车辆充电桩管理系统 本系统前台功能模块分为&#xff1a;首页功能和用户后台管理 后台功能模块分为&#xff1a;管理员功能和…

【前端】Vue-Cli 快速创建Vue3项目及一些项目初始化相关

文章目录 前言1. 安装1.1 安装 Vue 脚手架1.2 创建项目1.3 本地运行项目 2. 推送到仓库2.1 远程仓库准备2.2 关于gitIgnore文件2.3 通过git推送至远程仓库 3. 补充与总结3.1 npm 版本是否要升级到最新&#xff1f;3.2 这个项目建议的各种版本3.3 一般前端gitIgnore文件3.4 推荐…

UnityWebGL UGUI中文不显示问题

这是Unity编辑中效果 打包成webgl后的效果&#xff08;中文没有显示出来&#xff09; 解决方法 将Unity默认使用的Arial替换成中文字体。 1.找到电脑字体库&#xff08;win电脑字体库路径&#xff1a;C:\Windows\Fonts &#xff1b;Mac电脑搜索“字体册”&#xff09;。 2.将…

【更换yarn的位置】解决yarn和nodejs不在同一盘下产生的某些命令应用失败问题

具体问题我记得是command fail什么error&#xff0c;记不太清楚了&#xff0c;文章主要写了如何替换yarn路径&#xff0c;希望可以帮助到大家。

Jetpack Compose 架构层

点击查看&#xff1a;Jetpack Compose 架构层 官网 本页面简要介绍了组成 Jetpack Compose 的架构层&#xff0c;以及这种设计所依据的核心原则。 Jetpack Compose 不是一个单体式项目&#xff1b;它由一些模块构建而成&#xff0c;这些模块组合在一起&#xff0c;构成了一个完…

Zookeeper简介及选举机制

1.概述 Zookeeper是一个开源的&#xff0c;分布式的&#xff0c;为分布式框架&#xff08;如下图中的Hadoop和Hive&#xff09;提供协调服务的Apache项目。 工作机制&#xff1a;基于观察者设计模式的分布式服务管理框架&#xff0c;负责存储和管理数据&#xff0c;接受观察者…

RabbitMQ 部署方式选择

部署模式 RabbitMQ支持多种部署模式&#xff0c;可以根据应用的需求和规模选择适合的模式。以下是一些常见的RabbitMQ部署模式&#xff1a; 单节点模式&#xff1a; 最简单的部署方式&#xff0c;所有的RabbitMQ组件&#xff08;消息存储、交换机、队列等&#xff09;都运行在…

2023年12月CCF-GESP编程能力等级认证C++编程七级真题解析

一、单选题(共15题,共30分) 第1题 定义变量 double x ,如果下面代码输入为 100 ,输出最接近( )。 A:0 B:-5 C:-8 D:8 答案:B 第2题 对于下面动态规划方法实现的函数,以下选项中最适合表达其状态转移函数的为( )。 A: B: C: D:

【自然语言处理-二-attention注意力 是什么】

自然语言处理二-attention 注意力机制 自然语言处理二-attention 注意力记忆能力回顾下RNN&#xff08;也包括LSTM GRU&#xff09;解决memory问题改进后基于attention注意力的modelmatch操作softmax操作softmax值与hidder layer的值做weight sum 计算和将计算出来的和作为memo…

C++ 学习之Set容器

C++ Set容器构造和赋值 在C++中,std::set是一个用于存储唯一元素的有序集合容器。下面介绍一下std::set容器的构造和赋值操作: 构造 std::set 默认构造函数: std::set<int> mySet; // 创建一个空的set使用初始化列表构造: std::set<int> mySet