【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/5401.html

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

相关文章

以 RFID 为钥,开启民兵装备管理的科技之门

民兵配备的武器及装备涵盖了各式武器、弹药及军事技术设备&#xff0c;其管理的优良直接决定了民兵的作战效能。鉴于民兵装备普遍面临老化、维护支援不充分等问题&#xff0c;迫切需要迅速建立完善的民兵装备管理新体系。这一转变将推动民兵装备由数量扩张转向质量提升&#xf…

2025-1-21 Newstar CTF web week1 wp

文章目录 week1headach3会赢吗智械危机 week1 headach3 根据提示&#xff0c;在页面的请求头里找到flag flag{You_Ar3_R3Ally_A_9ooD_d0ctor} 会赢吗 打开控制台&#xff0c;拿到第一部分flag 将地址栏改为提示&#xff0c;去到下一关 控制台调用函数&#xff0c;得到flag …

C语言程序设计十大排序—选择排序

文章目录 1.概念✅2.选择排序&#x1f388;3.代码实现✅3.1 直接写✨3.2 函数✨ 4.总结✅5.十大排序 1.概念✅ 排序是数据处理的基本操作之一&#xff0c;每次算法竞赛都很多题目用到排序。排序算法是计算机科学中基础且常用的算法&#xff0c;排序后的数据更易于处理和查找。在…

(三)线性代数之二阶和三阶行列式详解

在前端开发中&#xff0c;尤其是在WebGL、图形渲染、或是与地图、模型计算相关的应用场景里&#xff0c;行列式的概念常常在计算变换矩阵、进行坐标变换或进行图形学算法时被使用。理解二阶和三阶行列式对于理解矩阵运算、旋转、平移等操作至关重要。下面&#xff0c;我将结合具…

通过docker overlay2目录名查找容器名和容器ID

参考&#xff1a;https://blog.csdn.net/beck_li/article/details/142059298 有时候经常会有个别容器占用磁盘空间特别大&#xff0c;这个时候就需要通过docker overlay2 日录名查找对应容器名. 1.首先进入到 /var/lib/docker/overlay2 目录下 #cd /var/lib/docker/overlay2 …

2025年入职/转行网络安全,该如何规划?网络安全职业规划

网络安全是一个日益增长的行业&#xff0c;对于打算进入或转行进入该领域的人来说&#xff0c;制定一个清晰且系统的职业规划非常重要。2025年&#xff0c;网络安全领域将继续发展并面临新的挑战&#xff0c;包括不断变化的技术、法规要求以及日益复杂的威胁环境。以下是一个关…

Vue平台开发三——项目管理页面

前言 对于多个项目的使用&#xff0c;可能需要进行项目切换管理&#xff0c;所以这里创建一个项目管理页面&#xff0c;登录成功后跳转这个页面&#xff0c;进行选择项目&#xff0c;再进入Home页面展示对应项目的内容。 一、实现效果图预览 二、页面内容 功能1、项目列表展…

深入解析人工智能中的协同过滤算法及其在推荐系统中的应用与优化

目录 什么是协同过滤算法核心原理基本步骤相似度计算代码实现详解1.流程图2.创建基础的数据结构存储用户评分数据3.计算用户相似度4.获取相似用户5.推荐方法 算法优化建议1. 数据预处理优化去除异常值和噪声数据进行数据标准化使用稀疏矩阵优化存储 2. 相似度计算优化使用局部敏…

【数据挖掘实战】 房价预测

本次对kaggle中的入门级数据集&#xff0c;房价回归数据集进行数据挖掘&#xff0c;预测房屋价格。 本人主页&#xff1a;机器学习司猫白 机器学习专栏&#xff1a;机器学习实战 PyTorch入门专栏&#xff1a;PyTorch入门 深度学习实战&#xff1a;深度学习 ok&#xff0c;话不多…

HTML 表单和输入标签详解

HTML 表单是网页与用户交互的重要工具&#xff0c;它允许用户输入数据并将其提交到服务器。表单在网页中的应用非常广泛&#xff0c;例如登录、注册、搜索、评论等功能都离不开表单。本文将详细介绍 HTML 表单及其相关标签的使用方法&#xff0c;帮助你全面掌握表单的设计与实现…

华为EC6110T-海思Hi3798MV310_安卓9.0_通刷-强刷固件包

华为EC6110T-海思Hi3798MV310_安卓9.0_通刷-强刷固件包 刷机教程说明&#xff1a; 适用机型&#xff1a;华为EC6110-T、华为EC6110-U、华为EC6110-M 破解总分为两个部分&#xff1a;拆机短接破解&#xff08;保留IPTV&#xff09;和OTT卡刷&#xff08;不保留IPTV&#xff09…

在centos上编译安装opensips【初级-默认安装】

环境&#xff1a;centos9 last opensips3.2 dnf update -y dnf install -y gcc make git automake libtool pcre-devel libxml2-devel \libcurl-devel postgresql-devel \bzip2-devel zlib-devel ncurses-devel libuuid-devel \libpcap-devel # 有报错的直接删除cd /usr/lo…

线性规划:机器学习中的优化利器

一、线性规划的基本概念 线性规划&#xff08;Linear Programming, LP&#xff09;是运筹学中数学规划的一个重要分支&#xff0c;用于在一组线性不等式的约束条件下&#xff0c;找到线性目标函数的最大值或最小值。其问题可以表述为&#xff1a; 在一组线性约束条件 s.t.&am…

基于AutoDL云计算平台+LLaMA-Factory训练平台微调本地大模型

1. 注册与认证 访问AutoDL官网&#xff1a;前往 AutoDL官网。 注册账号&#xff1a;完成注册流程。 实名认证&#xff1a;按照要求完成实名认证&#xff0c;以确保账号的合规性。 2. 选择GPU资源 进入算力市场&#xff1a;在官网首页点击“算力市场”菜单。 挑选GPU&#x…

04JavaWeb——Maven-SpringBootWeb入门

Maven 课程内容 初识Maven Maven概述 Maven模型介绍 Maven仓库介绍 Maven安装与配置 IDEA集成Maven 依赖管理 01. Maven课程介绍 1.1 课程安排 学习完前端Web开发技术后&#xff0c;我们即将开始学习后端Web开发技术。做为一名Java开发工程师&#xff0c;后端Web开发…

Linux内核编程(二十一)USB驱动开发-键盘驱动

一、驱动类型 USB 驱动开发主要分为两种&#xff1a;主机侧的驱动程序和设备侧的驱动程序。一般我们编写的都是主机侧的USB驱动程序。 主机侧驱动程序用于控制插入到主机中的 USB 设备&#xff0c;而设备侧驱动程序则负责控制 USB 设备如何与主机通信。由于设备侧驱动程序通常与…

< OS 有关 > 阿里云:轻量应用服务器 的使用 安装 Tailscale 后DNS 出错, 修复并替换 apt 数据源

VPS 配置 主机&#xff1a;vCPU x2, 512MB, 20GB位置&#xff1a;阿里云&#xff0c;日本.东京OS&#xff1a; ubuntu24.20 原因&#xff1a; 这篇是操作过程的记录文章。 2 个月前&#xff0c; 在阿里云买了台 vps 。当时本想放到韩国&#xff0c;因为它离北京近。 但最便…

【STM32-学习笔记-11-】RTC实时时钟

文章目录 RTC实时时钟一、RTC简介二、RTC框图三、RTC基本结构四、RTC操作注意事项五、RTC函数六、配置RTCMyRTC.c 七、示例&#xff1a;实时时钟①、main.c②、MyRTC.c③、MyRTC.h RTC实时时钟 一、RTC简介 RTC&#xff08;Real Time Clock&#xff09;实时时钟 RTC是一个独立…

Hadoop•搭建完全分布式集群

听说这里是目录哦 一、安装Hadoop&#x1f955;二、配置Hadoop系统环境变量&#x1f96e;三、验证Hadoop系统环境变量是否配置成功&#x1f9c1;四、修改Hadoop配置文件&#x1f36d;五、分发Hadoop安装目录&#x1f9cb;六、分发系统环境变量文件&#x1f368;七、格式化HDFS文…

网络通信---MCU移植LWIP

使用的MCU型号为STM32F429IGT6&#xff0c;PHY为LAN7820A 目标是通过MCU的ETH给LWIP提供输入输出从而实现基本的Ping应答 OK废话不多说我们直接开始 下载源码 LWIP包源码&#xff1a;lwip源码 -在这里下载 ST官方支持的ETH包&#xff1a;ST-ETH支持包 这里下载 创建工程 …