【SpringBoot实战】实现用户名密码登录

【SpringBoot实战】实现用户名密码登录

在Java项目中,实现用户名密码登录是最基本的功能。尽管实现起来不难,但也有些细节问题,故写下此篇博客作为记录。

1.创建用户表

CREATE TABLE `ad_user` (`id` int unsigned NOT NULL COMMENT '主键',`name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '登录用户名',`password` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '登录密码',`salt` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '盐',`nickname` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '昵称',`image` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '头像',`phone` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '手机号',`status` tinyint unsigned DEFAULT NULL COMMENT '状态\r\n            0 暂时不可用\r\n            1 永久不可用\r\n            9 正常可用',`email` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '邮箱',`login_time` datetime DEFAULT NULL COMMENT '最后一次登录时间',`created_time` datetime DEFAULT NULL COMMENT '创建时间',PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='管理员用户信息表'

其中,密码经过加salt之后再进行加密处理,即数据库中密码以加密的形式进行存储,可防止密码泄露。

2.创建实体类

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;import java.io.Serializable;
import java.util.Date;@Data
@TableName("ad_user")
public class AdUser implements Serializable {private static final long serialVersionUID = 1L;/*** 主键*/@TableId(value = "id", type = IdType.AUTO)private Integer id;/*** 密码、通信等加密盐*/@TableField("salt")private String salt;/*** 用户名*/@TableField("name")private String name;/*** 密码,md5加密*/@TableField("password")private String password;/*** 昵称*/@TableField("nickname")private String nickname;/*** 手机号*/@TableField("phone")private String phone;/*** 头像*/@TableField("image")private String image;/*** 状态0 暂时不可用1 永久不可用9 正常可用*/@TableField("status")private Integer status;/*** 邮箱*/@TableField("email")private String email;/*** 创建时间*/@TableField("created_time")private Date createdTime;/*** 最后一次登录时间*/@TableField("login_time")private Date loginTime;
}

其中,实体类实现了Serializable接口,并定义了serialVersionUID变量。
Serializable是一个对象序列化的接口,可将实体对象进行序列化。
如果我们没有声明一个serialVersionUID变量,接口会默认生成一个serialVersionUID,默认的serialVersinUID对于class的细节非常敏感,反序列化时可能会导致InvalidClassException异常,因此建议我们自定义一个serialVersionUID。

3.定义登录Dto

用户进行登录时,只需要输入用户名和密码。因此定义一个dto用于数据传输。

import lombok.Data;@Data
public class AdUserDto {private String name;private String password;
}

4.编写Controller层

@RestController
@RequestMapping("/login")
public class AdminLoginController {@Autowiredprivate AdminUserService adminUserService;@PostMapping("/in")public ResponseResult login(@RequestBody AdUserDto dto){return adminUserService.login(dto);}
}

其中,@RequestBody主要用来接收前端传递给后端的json字符串中的数据的(请求体中的数据的)。
使用@RequestBody接收数据时,一般都用POST方式进行提交。
@RequestBody最多只能有一个。

5.编写Mapper层

@Mapper
public interface AdminUserMapper extends BaseMapper<AdUser> {
}

6.编写Service层

service层使用了mybatis-plus,在Service接口需要继承IService,在serviceImpl实现类需要继承ServiceImpl。

public interface AdminUserService extends IService<AdUser> {public ResponseResult login(AdUserDto dto);
}

业务层实现用户名密码登录逻辑如下:

@Service
public class AdminUserServiceImpl extends ServiceImpl<AdminUserMapper, AdUser> implements AdminUserService {@Overridepublic ResponseResult login(AdUserDto dto) {// 1.检查参数是否为空if (StringUtils.isBlank(dto.getName()) || StringUtils.isBlank(dto.getPassword())){return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "用户名或密码为空");}// 2.查询用户是否存在AdUser adUser = getOne(Wrappers.<AdUser>lambdaQuery().eq(AdUser::getName, dto.getName()));if (adUser == null){return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);}// 3.对比密码是否正确String salt = adUser.getSalt();String password = dto.getPassword();// 采用md5码加密password = DigestUtils.md5DigestAsHex((password + salt).getBytes());if (password.equals(adUser.getPassword())){// 4.返回数据Map<String, Object> map = new HashMap<>();// 根据id获取tokenmap.put("token", AppJwtUtil.getToken(adUser.getId().longValue()));// 将salt和密码清空adUser.setSalt("");adUser.setPassword("");map.put("user", adUser);return ResponseResult.okResult(map);}else {return ResponseResult.errorResult(AppHttpCodeEnum.LOGIN_PASSWORD_ERROR);}}
}

7.Jwt工具类

导入依赖

<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version>
</dependency>

Jwt工具类中包含了token的生成及校验方法。
关于Jwt的刷新机制,建议参考如下文章:SpringBoot+JWT登录校验,以及JWT刷新机制

import io.jsonwebtoken.*;import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.*;public class AppJwtUtil {// TOKEN的有效期一小时(S)private static final int TOKEN_TIME_OUT = 3_600;// 加密私钥private static final String TOKEN_ENCRY_KEY = "MDk4ZjZiY2Q0NjIxZDM3M2NhZGU0ZTgzMjYyN2I0ZjY";// 最小刷新间隔(S)private static final int REFRESH_TIME = 300;// 生产IDpublic static String getToken(Long id){Map<String, Object> claimMaps = new HashMap<>();claimMaps.put("id",id);long currentTime = System.currentTimeMillis();return Jwts.builder().setId(UUID.randomUUID().toString()).setIssuedAt(new Date(currentTime))  //签发时间.setSubject("system")  //说明.setIssuer("daybreak") //签发者信息.setAudience("app")  //接收用户.compressWith(CompressionCodecs.GZIP)  //数据压缩方式.signWith(SignatureAlgorithm.HS512, generalKey()) //加密方式.setExpiration(new Date(currentTime + TOKEN_TIME_OUT * 1000))  //过期时间戳.addClaims(claimMaps) //claim信息.compact();}/*** 获取token中的claims信息* @param token* @return*/private static Jws<Claims> getJws(String token) {return Jwts.parser().setSigningKey(generalKey()).parseClaimsJws(token);}/*** 获取payload body信息* @param token* @return*/public static Claims getClaimsBody(String token) {try {return getJws(token).getBody();}catch (ExpiredJwtException e){return null;}}/*** 获取hearder body信息* @param token* @return*/public static JwsHeader getHeaderBody(String token) {return getJws(token).getHeader();}/*** 是否过期* @param claims* @return -1:有效,0:有效,1:过期,2:过期*/public static int verifyToken(Claims claims) {if(claims==null){return 1;}try {claims.getExpiration().before(new Date());// 需要自动刷新TOKENif((claims.getExpiration().getTime()-System.currentTimeMillis())>REFRESH_TIME*1000){return -1;}else {return 0;}} catch (ExpiredJwtException ex) {return 1;}catch (Exception e){return 2;}}/*** 由字符串生成加密key* @return*/public static SecretKey generalKey() {byte[] encodedKey = Base64.getEncoder().encode(TOKEN_ENCRY_KEY.getBytes());SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");return key;}}

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

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

相关文章

代码随想录算法训练营第五十五天 _ 动态规划_392. 判断子序列、115.不同的子序列。

学习目标&#xff1a; 动态规划五部曲&#xff1a; ① 确定dp[i]的含义 ② 求递推公式 ③ dp数组如何初始化 ④ 确定遍历顺序 ⑤ 打印递归数组 ---- 调试 引用自代码随想录&#xff01; 60天训练营打卡计划&#xff01; 学习内容&#xff1a; 392. 判断子序列 这个题目就是 …

消息队列kafka详解:Kafka原理分析总结

一、概述 Kakfa起初是由LinkedIn公司开发的一个分布式的消息系统&#xff0c;后成为Apache的一部分&#xff0c;它使用Scala编写&#xff0c;以可水平扩展和高吞吐率而被广泛使用。目前越来越多的开源分布式处理系统如Cloudera、Apache Storm、Spark等都支持与Kafka集成。 Kaf…

EasyMock介绍及安装方法(亲测可用)

1. EasyMock介绍 Easy Mock是一个可视化&#xff0c;并且能快速生成模拟数据的服务。以项目管理的方式组织Mock List&#xff0c;能帮助我们更好的管理Mock数据&#xff0c;不怕丢失。 2. EasyMock魅力 前后端分离&#xff1a;让前端工程师独立于后端进行开发 增加单元测试…

SGPIO介紹

什么是SGPIO&#xff1f; Serial General Purpose Input Output (SGPIO) is a method to serialize general purpose IO signals. SGPIO defines the communication between an initiator (e.g. a host bus adapter) and a target (e.g. a backplaneholding disk drives). The …

美易官方:投行把脉明年油市,花旗悲观、高盛最看涨

投行把脉明年油市&#xff0c;花旗悲观、高盛最看涨 随着全球经济的逐步复苏&#xff0c;石油市场的走势备受关注。各大投行对明年油市的预测也各不相同&#xff0c;其中花旗集团较为悲观&#xff0c;而高盛集团则最为看涨。 华尔街的预测师们认为明年原油价格有一定的恢复空间…

最小窗口子串算法题——Java解答

题目&#xff1a;最小窗口子串 题目描述&#xff1a; 给你一个字符串 s 和一个字符串 t&#xff0c;返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串&#xff0c;则返回空字符串 ""。 注意&#xff1a; 对于 t 中重复的字符&#xff…

Axure的交互与情形,事件,动作

交互样式 交互样式是指当用户与原型进行交互时&#xff0c;元素所呈现出的视觉效果。在Axure中&#xff0c;可以通过设置交互样式来调整元素在交互过程中的外观&#xff0c;例如改变颜色、大小、位置等。 交互事件 交互事件是指在用户与原型进行交互时触发的动作。在Axure中&…

记录选择计算机专业后的这十二年,感谢当初自己选择了计算机行业

前言 这篇文章是对我这些年工作经历的回顾&#xff0c;您不会通过这篇文章提升自己的技术能力。如果您还未毕业&#xff0c;但是我希望您可以通过我的故事&#xff0c;简单了解这个行业可以能做什么&#xff0c;你可以做些什么。如果您初入此行业&#xff0c;希望我的故事可以…

一次应急响应记录

背景&#xff1a; 周五晚上&#xff0c;我健身完回到宿舍收到qq消息&#xff0c;原来是安全厂商在扫描资产时&#xff0c;发现一批openssh漏洞如下图&#xff1a; 其实我是一名小白&#xff0c;我的第一反应就是升级openssh版本。但是这里问题又来了&#xff0c;我们内网主机是…

Python 自动化之收发邮件(一)

imapclient / smtplib 收发邮件 文章目录 imapclient / smtplib 收发邮件前言一、基本内容二、发送邮件1.整体代码 三、获取邮件1.整体代码 总结 前言 简单给大家写个如何用Python进行发邮件和查看邮件教程&#xff0c;希望对各位有所帮助。 一、基本内容 本文主要分为两部分…

基于ssm在线作业管理系统的设计与实现论文

摘 要 网络技术和计算机技术发展至今&#xff0c;已经拥有了深厚的理论基础&#xff0c;并在现实中进行了充分运用&#xff0c;尤其是基于计算机运行的软件更是受到各界的关注。加上现在人们已经步入信息时代&#xff0c;所以对于信息的宣传和管理就很关键。因此学生作业信息的…

Web Worker的快速理解与简单应用

Web Worker 是一种在浏览器环境中运行的脚本它在主线程之外运行&#xff0c;可以在后台执行计算密集型或需要长时间运行的任务&#xff0c;而不会阻塞主线程的执行。Web Worker 通过在独立的线程中执行&#xff0c;可以提高页面的性能和响应性。 实现流程&#xff1a; 主线程&a…

补题与总结:牛客小白月赛83(B~F)

文章目录 写在最前面的复盘B-小天的魔法&#xff08;贪心 模拟 双指针&#xff09;C-小天的 Minecraft&#xff08;概率&#xff09;D-小天的子序列&#xff08;预处理 排列组合&#xff09;E-小天的贪吃蛇&#xff08;模拟&#xff09;F-小天的 AB&#xff08;结论题&#xff…

举个栗子!Tableau 技巧(261):自由切换图表的背景颜色

数据粉反馈了一个有趣的需求&#xff1a;Tableau 图表的背景颜色可以设置多个&#xff0c;然后按需切换么&#xff1f; 我们知道&#xff0c;图表的背景颜色对于可视化分析呈现来说非常重要。大部分情况下&#xff0c;我们会固定使用一种背景色。 如果确实需要切换图表背景颜…

K8s内容器拓扑图工具

1.背景&#xff1a;随着线上容器越来越多&#xff0c;需要一个可视化的方式展示各个容器之间的拓扑图。 2.需求&#xff1a;轻量级&#xff0c;部署方便。 3.部署 helm repo add groundcover https://helm.groundcover.com/ helm repo update helm install caretta --namespa…

力扣题目学习笔记(OC + Swift) 11

11.盛最多水的容器 给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回容器可以储存的最大水量。 说明&#xff1a;你不能倾…

springboot(ssm儿童慈善管理系统 儿童捐赠平台 Java系统

springboot(ssm儿童慈善管理系统 儿童捐赠平台 Java系统 开发语言&#xff1a;Java 框架&#xff1a;ssm/springboot vue JDK版本&#xff1a;JDK1.8&#xff08;或11&#xff09; 服务器&#xff1a;tomcat 数据库&#xff1a;mysql 5.7&#xff08;或8.0&#xff09; 数…

代码随想录算法训练营第二十天 | 二叉搜索树

目录 力扣题目 力扣题目记录 654.最大二叉树 617.合并二叉树 用值 用指针 700.二叉搜索树中的搜索 递归 迭代 98.验证二叉搜索树 总结 力扣题目 用时&#xff1a;2h 1、654.最大二叉树 2、617.合并二叉树 3、700.二叉搜索树中的搜索 4、98.验证二叉搜索树 力扣…

JupyterNotebook VS JupyterLab 如果jupyter安装成功,点击jupyterlab即可进入lab环境

简介 JupyterNotebook 是一个款以网页为基础的交互计算环境&#xff0c;可以创建Jupyter的文档&#xff0c;支持多种语言&#xff0c;包括Python, Julia, R等等。一般来说&#xff0c;如果是使用R语言的话&#xff0c;使用Rstudio居多&#xff0c;使用Python的话&#xff0c;使…

如何快速优化几千万数据量的订单表

前言 为了保证有一个更健康的身体&#xff0c;所以慢慢降低了更新频率&#xff0c;在有了更多休息时间的前提下&#xff0c;思考了一下接下来准备分享的一些内容。 决定在更新一些技术干货的同时&#xff0c;会穿插一些架构知识&#xff0c;放在单独的专栏里面&#xff0c;希…