【wiki知识库】08.添加用户登录功能--后端SpringBoot部分

目录

一、今日目标 

二、SpringBoot后端实现

2.1 新增UserLoginParam

2.2 修改UserController

2.3 UserServiceImpl代码

2.4 创建用户上下文工具类

2.5 通过token校验用户(重要)

2.6 创建WebMvcConfig

2.7 用户权限校验拦截器


一、今日目标 

上篇文章链接:【wiki知识库】08.添加用户登录功能--前端Vue部分修改-CSDN博客

这篇文章主要是实现一下用户登录功能的后端部分,登录功能需要使用redis,不懂redis可以看我之前的一篇文章。

Redis文章链接:【Spring】SpringBoot整合Redis,用Redis实现限流(附Redis解压包)_springboot 限流 redis-CSDN博客

那么为什么要用到Redis呢?

这个问题关系到整个系统的用户校验,当我们登录成功的时候,后端会生成一个用于用户校验的token值,然后把这个值传给前端,每次用户请求后端的时候都要带上这个token值,这个token的值当中记录了当前登录的用户是谁,还有过期时间等信息,这样子就可以防止那些没有登陆的用户去直接访问我们的后端调用接口。所以这个token还是需要妥善保管的,一旦token丢失别人就可能用你的token去发送请求,修改你的数据。

二、SpringBoot后端实现

2.1 新增UserLoginParam

这里也做了校验,其实这个事情完全可以放到前端实现,但是也要考虑到有直接调用接口的情况,这时也要给出错误提示。

@Data
public class UserLoginParam {@NotEmpty(message = "【用户名】不能为空")private String loginName;@NotEmpty(message = "【密码】不能为空")@Pattern(regexp = "^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,32}$", message = "【密码】规则不正确")private String password;}

2.2 修改UserController

直接上代码吧。这里拿到了用户的账号和用户的密码,然后判断加密后的密码和数据库中取出来的用户密码是否相同,如果相同那么就可以登陆。登陆后通过工具类生成一个不会重复的Long类型的值作为该用户的token,然后以token为key,登录用户创建的对象作为值,保存到redis当中,以便于后续用户访问接口时,通过用户token来判断是哪个用户访问接口。

  @PostMapping("/login")public CommonResp login(@Valid @RequestBody UserLoginParam req) {req.setPassword(DigestUtils.md5DigestAsHex(req.getPassword().getBytes()));System.out.println(req);UserLoginVo userLoginResp = userService.login(req);Long token = snowFlake.nextId();userLoginResp.setToken(token.toString());redisTemplate.opsForValue().set(token.toString(), JSONObject.toJSONString(userLoginResp), 3600 * 24, TimeUnit.SECONDS);return new CommonResp(true,"登录成功",userLoginResp);}@GetMapping("/logout/{token}")public CommonResp logout(@PathVariable String token) {boolean res = redisTemplate.delete(token);String message = Boolean.TRUE.equals(res) ? "登出成功":"登出失败";return new CommonResp(true,message,null);}

2.3 UserServiceImpl代码

这个代码没有什么好说的,就是查找一次数据库进行账号密码的匹配。

public UserLoginVo login(UserLoginParam req) {User userDb = selectByLoginName(req.getLoginName());if (ObjectUtils.isEmpty(userDb)) {// 用户名不存在throw new RuntimeException("用户名不存在");} else {if (userDb.getPassword().equals(req.getPassword())) {// 登录成功UserLoginVo userLoginResp = CopyUtil.copy(userDb, UserLoginVo.class);return userLoginResp;} else {// 密码不对throw new RuntimeException("密码错误");}}}

2.4 创建用户上下文工具类

这个工具类用户用户登录后保存当前用户的上下文。

public class LoginUserContext implements Serializable {private static ThreadLocal<UserLoginVo> user = new ThreadLocal<>();public static UserLoginVo getUser() {return user.get();}public static void setUser(UserLoginVo user) {LoginUserContext.user.set(user);}}

2.5 通过token校验用户(重要)

校验用户token需要使用到拦截器或者过滤器,这里我使用拦截器进行用户token的校验。整体的校验流程如下

 以下就是登录拦截器的代码,

/*** 拦截器:Spring框架特有的,常用于登录校验,权限校验,请求日志打印*/
@Component
public class LoginInterceptor implements HandlerInterceptor {private static final Logger LOG = LoggerFactory.getLogger(LoginInterceptor.class);@Resourceprivate RedisTemplate redisTemplate;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// OPTIONS请求不做校验,// 前后端分离的架构, 前端会发一个OPTIONS请求先做预检, 对预检请求不做校验if (request.getMethod().toUpperCase().equals("OPTIONS")) {return true;}String path = request.getRequestURL().toString();LOG.info("接口登录拦截:,path:{}", path);//获取header的token参数String token = request.getHeader("token");LOG.info("登录校验开始,token:{}", token);if (token == null || token.isEmpty()) {LOG.info("token为空,请求被拦截");response.setStatus(HttpStatus.UNAUTHORIZED.value());return false;}Object object = redisTemplate.opsForValue().get(token);// 证明redis中的用户信息过期了,需要重新登陆if (object == null) {LOG.warn("token无效,请求被拦截");response.setStatus(HttpStatus.UNAUTHORIZED.value());return false;} else {LOG.info("已登录:{}", object);LoginUserContext.setUser(JSON.parseObject((String) object, UserLoginVo.class));return true;}}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {}
}

接下来要把这个拦截器注册到配置当中。


2.6 创建WebMvcConfig

在config包下创建该类。这个类当中配置了两个拦截器,一个是登录拦截器,另一个是用户权限校验拦截器。用户校验拦截器下边再说。登录拦截器只需要部分接口进行拦截就可以了,毕竟有的接口不需要登陆用户就可以访问。

有一点值得注意的是,在这个配置类中配置的拦截器的顺序会影响校验结果,校验的流程是根据你配置的拦截器的顺序从上往下校验的,如果你把拦截器配置写反了就会出错。

addInterceptor注册一个拦截器
addPathPatterns该拦截器需要拦截的路径
excludePathPatterns该拦截器不需要拦截的路径
@Configuration
public class SpringMvcConfig implements WebMvcConfigurer {@ResourceLoginInterceptor loginInterceptor;@ResourceActionInterceptor actionInterceptor;public void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(loginInterceptor).addPathPatterns("/**").excludePathPatterns("/test/**","/redis/**","/user/login","/user/logout/**","/category/all","/ebook/list","/doc/all/**","/doc/find-content/**",);registry.addInterceptor(actionInterceptor).addPathPatterns("/*/save","/*/delete/**","/*/reset-password");}
}

2.7 用户权限校验拦截器

看到下方的代码你应该知道了用户上下文的作用,通过用户上下文拿到用户的信息来判断该用户是否有访问该接口的权利,我们拒绝非admin用户外的用户进行增删改操作。

但是这种方法有点不太好不知道你们有没有感觉到,一旦用户多了之后,如果你想给用户分配权限,你就要添加很多的用户在这里。所以一种更好的方式就是RBAC权限校验,大家可以自己了解一下,也有更好的权限校验框架SpringSecurity,但是作为一个比较简单的项目,引入这个框架的学习成本就太大了。

/*** 拦截器:Spring框架特有的,常用于登录校验,权限校验,请求日志打印*/
@Component
public class ActionInterceptor implements HandlerInterceptor {private static final Logger LOG = LoggerFactory.getLogger(ActionInterceptor.class);@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {// OPTIONS请求不做校验,// 前后端分离的架构, 前端会发一个OPTIONS请求先做预检, 对预检请求不做校验if ("OPTIONS".equals(request.getMethod().toUpperCase())) {return true;}UserLoginVo userLoginResp = LoginUserContext.getUser();if ("admin".equals(userLoginResp.getLoginName())) {// admin用户不拦截return true;}LOG.info("操作被拦截");response.setStatus(HttpStatus.OK.value());CommonResp commonResp = new CommonResp(false,"普通用户暂不开放增删改操作",null);response.setContentType("application/json;charset=UTF-8");response.setCharacterEncoding("UTF-8");response.getWriter().print(JSONObject.toJSON(commonResp));return false;}}

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

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

相关文章

【大模型】大模型指令微调的“Prompt”模板

文章目录 一、微调数据集格式二、常用的指令监督微调模板2.1 指令跟随格式&#xff08;Alpaca&#xff09;2.2 多轮对话格式&#xff08;ShareGPT&#xff09;2.3 其他形式2.4 常见模板 参考资料 一、微调数据集格式 在进行大模型微调的过程中&#xff0c;我们会发现“Prompt”…

mysql 日志爆满,删除日志文件,定时清理日志

今天发现网站不能正常访问&#xff0c;于是登陆服务器查找问题。 机智的我随手用命令&#xff1a;df -l 发现 硬盘爆满了&#xff0c;于是就知道问题所在了。 Filesystem 1K-blocks Used Available Use% Mounted on/dev/xvda1 20641404 16963004 16929876 10…

安捷伦N9918A是德keysight N9918B 30khz-26.5g频谱分析仪

Agilent N9918A、Keysight N9918B、 FieldFox 手持式射频和微波组合分析仪&#xff0c;30 kHz - 26.5 GHz 附加功能&#xff1a; 30 kHz 至 26.5 GHz动态范围&#xff1a;100 dBCAT&#xff1a;故障点距离、回波损耗、电缆损耗VNA&#xff1a;S11、S21、S22、S12、幅度和相位…

PMP考试一定要考到3A吗?怎么备考?

PMP&#xff08;Project Management Professional&#xff09;认证是全球公认的项目管理专业人士资格认证&#xff0c;它代表着项目管理领域的高水平标准。 在备考PMP考试时&#xff0c;有些赛宝关心是否需要考到3A&#xff08;即三个领域均为Above Target&#xff0c;超出目标…

GoFly快速开发框架代码市场使用说明

说明 我们框架坚持开源的项目绝不能存在收费项目&#xff0c;所以我们gofly快速开发开源版没有内置代码仓插件&#xff0c;因此需要使用代码市场中的代码包需要再企业版中使用&#xff0c;代码市场插件如下&#xff1a; 图1、社区-代码市场​​​​ 他和企业版管理后台的代码仓…

慢SQL优化的30个思路方案整理

文章目录 &#xff08;1&#xff09;索引优化&#xff08;2&#xff09;查询重构&#xff08;3&#xff09;减少数据扫描量&#xff08;4&#xff09;利用缓存&#xff08;5&#xff09;分区表&#xff08;6&#xff09;优化排序和分组&#xff08;7&#xff09;业务查询条件限…

openfoam模拟时取消报错Floating point exception (core dumped),从而看到具体错误内容

一、理论简介&#xff1a; unset FOAM_SIGFPE 是用于在 OpenFOAM 环境中解除对浮点异常&#xff08;Floating Point Exception, FPE&#xff09;的信号处理。 FOAM_SIGFPE 环境变量的作用 在 OpenFOAM 中&#xff0c;FOAM_SIGFPE 环境变量用于控制程序对浮点异常&#xff08…

【设计模式】设计模式之观察者模式

文章目录 观察者模式什么是观察者模式引入组成UML图代码实现1. 定义观察者接口2. 定义主题接口3. 实现具体观察者4. 实现具体被观察者5.测试 应用场景优点缺点 观察者模式 什么是观察者模式 观察者模式&#xff08;Observer Pattern&#xff09;是一种设计模式 它定义了一种…

BTS4140N:高侧电源开关芯片中文数据手册

芯片概述 &#xff1a; BTS4140N是一款智能高压侧电源开关N沟道垂直功率MOSFET&#xff0c;带电荷泵和电流控制输入、采用智能SIPMOS技术单片集成&#xff0c;提供嵌入式保护和诊断功能。 芯片特征描述 电流控制输入短路保护电流限制欠电压时关断过压保护&#xff08;包括负载突…

【mars3d】GraphicLayer遍历添加数据,正确拿到数据

import * as mars3d from "mars3d"export let map // mars3d.Map三维地图对象 export let graphicLayer // 矢量数据图层 export const mapOptions {scene: {center:{"lat":30.577085,"lng":116.885511,"alt":45203.5,"heading&…

Jenkins参数化构建

目录 一. 准备ansible 二. Gitlab新建子项目 三. Jenkins建立任务&#xff0c;进行初步配置 四. 导入nginx主机的公钥 五. 配置ansible执行脚本 六. 构建测试 一. 准备ansible 在jenkins主机中安装ansible [rootjenkins ~]# yum install -y epel-release [rootjenkins…

【学习笔记】Day 6

一、进度概述 1、《地震勘探原理》第二章 2、“DenseNet” 周报分享 二、详情 1、《地震勘探原理》第二章 注&#xff1a;本来的打算是逐章整理&#xff0c;但是在听老师指导后&#xff0c;明晰了学习目的。故学习方法更改为侧重 “刷” 。不求一遍全弄懂&#xff0c…

AI在商品计划领域的应用

在现代商业环境中&#xff0c;AI驱动的商品计划优化已经成为企业有效管理资源和提高利润的关键因素。 市场预测与库存管理 精准市场预测&#xff1a;以某著名零售品牌为例&#xff0c;该品牌引入了一种基于AI的智能分析工具&#xff0c;帮助实现了精准的市场预测与库存管理。根…

【Linux基础】Linux基本指令(一)

目录 前言一&#xff0c; ls指令二&#xff0c;pwd指令三&#xff0c;cd指令3.1 当前目录与上级目录3.2 绝对路径和相对路径3.3 tree指令 四&#xff0c;创建一个普通文件或目录4.1 touch指令4.2 mkdir指令 五&#xff0c;删除目录或文件5.1 rmdir指令5.2 rm 指令 六&#xff0…

细节持续跟新

1.input的自带光标如何去除 2.阻止事件冒泡 3.获取父亲兄弟的innertext 4.画表格 参考博主链接 前端-HTML表格制作_哔哩哔哩_bilibili 美化

不同环境下RabbitMQ的安装-3 操作RabbitMQ

前面两篇从不同环境下RabbitMQ的安装-1 为什么要使用消息服务 到同环境下RabbitMQ的安装-2 ARM架构、X86架构、Window系统环境下安装RabbitMQ介绍了关于如何在ARM架构、X86架构和Window系统下如何安装&#xff0c;各位小伙伴可以根据自己的实际开发场景参考安装。 到本篇是一些…

【ARM】CMSIS 软件标准接口

目录 CMSIS&#xff1a;Cortex Microcontroller Software Interface Standard1. 概述2. CMSIS-Core2.1 概述2.2 关键组件2.3 示例代码2.4 详细解释 3. CMSIS-DSP3.1 概述3.2 关键组件3.3 示例代码3.4 详细解释 4. CMSIS-RTOS4.1 概述4.2 关键组件4.3 示例代码4.4 详细解释 5. C…

【案例40】Apache中mod_proxy模块的使用

NC中间件 应用场景&#xff1a;配置了apache的情况&#xff0c;包括uap集群&#xff0c;配置https等场景下均适用&#xff1b;如果是单机&#xff08;NC单结点情况不存在问题&#xff0c;则不用配置这项; was环境也不用配置此项。&#xff09; 解决方案&#xff1a;按如下两…

Spring Boot 3.x Rest API最佳实践之API设计

本系列教程将会以企业中API基础功能封装为目标&#xff0c;用最新的Spring Boot 3.x版本来逐步搭建和完善Rest API项目基础架构&#xff0c;并结合实际电商项目中API的实现需求来进行最佳实践。如果觉得对你有帮助&#xff0c;记得点赞收藏&#xff0c;关注小卷&#xff0c;后续…

React性能之--如何避免组件重复渲染?

在react中&#xff0c;我们会发现存在组件会重复渲染&#xff0c;虽然说如果项目不大的话&#xff0c;这点影响不大&#xff0c;但是我们还是尽量避免组件渲染比较好&#xff0c;养成好习惯&#xff0c;尽可能让不管是大小项目&#xff0c;都让性能尽可能优化 。那我们如何避免…