java后端之登录认证

- 基础登录功能:根据提供的用户名和密码判断是否存在于数据库
LoginController.java
@RestController
@Slf4j
public class LoginController {@Autowiredprivate UserService userService;@PostMapping("/login")public Result login(@RequestBody User user) {log.info("user: {}", user);User u = userService.login(user);return u != null ? Result.success(u) : Result.error("用户名或密码错误");}
}
UserController.java
@Service
public class UserServiceImpl implements com.diaryback.Service.UserService {@Autowiredprivate UserMapper userMapper;public User login(User user) {return userMapper.getUserByIdAndPassword(user);}
}
登录校验
在用户未登录情况下访问需要登录才能使用的业务,会跳转到登录界面

会话技术
- 会话:用户通过浏览器访问服务器资源时建立会话,直到一方断开连接会话结束。一次会话中可以包含多次请求和响应
- 会话跟踪:服务器需要识别多个请求是否来自同一个浏览器,以便在同一个会话的多个请求之间共享数据
Cookie
服务器端存储Cookie,响应时自动加上Cookie到客户端,客户端下次请求会自动加上cookie
不允许跨域请求

Session
Session技术基于cookie,首次访问服务端时创建session,并将sessionID附加到cookie

令牌
令牌中存储用户的身份信息以及需要共享的数据,存储在客户端

JWT令牌
jwt:JSON Web Token,将原始JSON数据进行安全封装
jwt三组成部分:
- Header:记录令牌类型,签名算法
- Payload:有效载荷,携带自定义信息,默认信息和有效期等
- Signature:签名,确保安全性。将header和payload加密计算而来
引入依赖:
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.12.3</version></dependency>
生成jwt字符串:需要指定签名算法、密钥以及自定义内容和过期时间
/*** 测试生成JWT*/@Testpublic void testGenJWT(){Map<String, Object> claims = new HashMap<>();claims.put("id", 1);claims.put("name", "maria");String jwt = Jwts.builder().signWith(SignatureAlgorithm.HS256, "AlexandarHamiltonWeAreWaitingInTheWingsForYou")//设置加密方式和加密密钥.claims(claims)//设置自定义内容.expiration(new Date(System.currentTimeMillis() + 3600 * 1000))//设置有效期为一个小时.compact();//生成字符串System.out.println(jwt);}
解析时需要指定签名的密钥
/*** 测试解析JWT*/@Testpublic void testParseJWT() {Claims claims = Jwts.parser().setSigningKey("AlexandarHamiltonWeAreWaitingInTheWingsForYou")//设置解密密钥.build().parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoibWFyaWEiLCJpZCI6MSwiZXhwIjoxNzM3NzExMjQ3fQ.AD2hdUzHdzq9qA0ZulvOyWA857tuRUWChnEX2P1ebcI").getBody();System.out.println(claims);}
JWT工具类:jwtUtil
package com.diaryback.Utils;import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;import java.util.Date;
import java.util.Map;public class JwtUtil {private static String signKey = "AlexandarHamiltonWeAreWaitingInTheWingsForYou";private static Long expire = 432000000L;/*** 生成jwt令牌*/public static String generateJwt(Map<String, Object> claims){String jwt = Jwts.builder().addClaims(claims).signWith(SignatureAlgorithm.HS256, signKey).setExpiration(new Date(System.currentTimeMillis() + expire)).compact();return jwt;}/*** 解析jwt令牌*/public static Claims parseJwt(String jwt){Claims claims = Jwts.parser().setSigningKey(signKey).build().parseClaimsJws(jwt).getBody();return claims;}
}
Filter过滤器
可以拦截对资源的请求,通常用于登录校验、统一编码等
- 定义Filter:定义一个类,实现Filter接口,重写所有方法(init(), destroy(), doFilter())
- 配置Filter:Filter类加上@WebFilter注解,配置拦截资源的路径,同时启动类加上@ServletComponentScan开启Servlet组件支持
拦截路径的配置:

过滤器链:一个web应用中可以配置多个过滤器行程过滤器链
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.annotation.WebFilter;import javax.servlet.*;
import java.io.IOException;@WebFilter(urlPatterns = "/*")
public class DemoFilter implements jakarta.servlet.Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {
// Filter.super.init(filterConfig);System.out.println("初始化过滤器");}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("Demo 执行过滤操作...放行前逻辑");//放行filterChain.doFilter(servletRequest, servletResponse);System.out.println("Demo 执行过滤操作...放行后逻辑");}@Overridepublic void destroy() {
// Filter.super.destroy();System.out.println("销毁过滤器");}
}
登录校验的Filter流程:

LoginFilter.java
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONPObject;
import com.diaryback.Pojo.Result;
import com.diaryback.Utils.JwtUtil;
import jakarta.servlet.*;
import jakarta.servlet.annotation.WebFilter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.http.HttpRequest;@Slf4j
@WebFilter(urlPatterns = "/*")
public class LoginFilter implements Filter {@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {HttpServletRequest req = (HttpServletRequest) servletRequest;//强制类型转换,将ServletRequest转换为其子类HttpServletRequestHttpServletResponse resp = (HttpServletResponse) servletResponse;String url = req.getRequestURL().toString();log.info("请求的url:{}", url);// 如果是登录请求则放行if(url.contains("login")){log.info("登录请求,放行");filterChain.doFilter(servletRequest, servletResponse);return;}//获取请求头中的令牌String jwt = req.getHeader("token");//判断请求头中是否有令牌if(!StringUtils.hasLength(jwt)){log.info("未登录,不允许访问");Result error = Result.error("NOT_LOGIN");//将Result转换为JSON格式传递给前端,使用fastJson包String notLogin = JSON.toJSONString(error);resp.getWriter().write(notLogin);return;}//解析token校验令牌try {JwtUtil.parseJwt(jwt);} catch (Exception e) {//jwt解析失败e.printStackTrace();log.info("解析失败,不允许访问");Result error = Result.error("NOT_LOGIN");String notLogin = JSON.toJSONString(error);resp.getWriter().write(notLogin);return;}//放行log.info("已登录,放行");filterChain.doFilter(servletRequest, servletResponse);}
}
Interceptor拦截器
Interceptor:作用类似于Filter,拦截请求,在指定方法调用前后执行预先设定的代码
- 定义拦截器,实现HandlerInterceptor接口,并重写所有方法(preHandler, postHandle, afterCompletion)
- 注册拦截器,需要在配置类中注册
LoginCheckInterceptor.java
package com.diaryback.Interceptor;import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;@Component //将拦截器交给Spring容器管理
public class LoginCheckInterceptor implements HandlerInterceptor {@Override //请求处理前调用,返回false则请求不会被处理public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("preHandle执行");return true;}@Override //请求处理后调用,但在视图渲染前public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("postHandle执行");}@Override //请求处理后调用,视图渲染后public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("afterCompletion执行");}
}
WebConfig.java
package com.diaryback.config;import com.diaryback.Interceptor.LoginCheckInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration //声明是配置类
public class WebConfig implements WebMvcConfigurer {@Autowiredprivate LoginCheckInterceptor loginCheckInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {//添加拦截器registry.addInterceptor(loginCheckInterceptor).addPathPatterns("/**");}
}
拦截路径:addPathPatterns()定义需要拦截哪些资源,excludePathPatterns()定义不需要拦截哪些资源

拦截器执行流程:

登录校验拦截器
```java
package com.diaryback.Interceptor;import com.alibaba.fastjson.JSONObject;
import com.diaryback.Pojo.Result;
import com.diaryback.Utils.JwtUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;@Slf4j
@Component //将拦截器交给Spring容器管理
public class LoginCheckInterceptor implements HandlerInterceptor {@Override //请求处理前调用,返回false则请求不会被处理public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String url = request.getRequestURL().toString();log.info("preHandle执行,url: {}", url);if(url.contains("login")){log.info("放行");return true;}String jwt = request.getHeader("token");//检查是否有令牌if(!StringUtils.hasLength(jwt)){log.info("未登录");Result error = Result.error("NOT_LOGIN");String notLogin = JSONObject.toJSONString(error);response.getWriter().write(notLogin);return false;}//解析令牌try {JwtUtil.parseJwt(jwt);} catch (Exception e) {e.printStackTrace();log.info("令牌无效");Result error = Result.error("NOT_LOGIN");String notLogin = JSONObject.toJSONString(error);response.getWriter().write(notLogin);return false;}//放行log.info("放行");return true;}@Override //请求处理后调用,但在视图渲染前public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("postHandle执行");}@Override //请求处理后调用,视图渲染后public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("afterCompletion执行");}
}
异常处理
定义全局异常处理器

import com.diaryback.Pojo.Result;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;/*** 全局异常处理*/
@RestControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(Exception.class)//指定处理的异常类型public Result ex(Exception ex){ex.printStackTrace();return Result.error("服务器异常");}
}相关文章:
java后端之登录认证
基础登录功能:根据提供的用户名和密码判断是否存在于数据库 LoginController.java RestController Slf4j public class LoginController {Autowiredprivate UserService userService;PostMapping("/login")public Result login(RequestBody User user) {…...
【矩阵二分】力扣378. 有序矩阵中第 K 小的元素
给你一个 n x n 矩阵 matrix ,其中每行和每列元素均按升序排序,找到矩阵中第 k 小的元素。 请注意,它是 排序后 的第 k 小元素,而不是第 k 个 不同 的元素。 你必须找到一个内存复杂度优于 O(n2) 的解决方案。 示例 1࿱…...
C语言-构造数据类型
1、构造数据类型 结构体、共用体、枚举。 2、结构体 1、结构体的定义 结构体是一个自定义的复合数据类型,它允许将不同类型的数据组合在一起。 struct 结构体名 {数据类型1 成员变量1;数据类型2 成员变量2;数据类型3 成员变量3;数据类型4 成员变量4; } 2、结构体变…...
鸿蒙next 自定义日历组件
效果图预览 20250124-113957 使用说明 1.选择日期左右箭头,实现每月日历切换,示例中超出当前月份,禁止进入下一月,可在代码更改 2.日历中显示当前选择的日期,选中的日期颜色可自定义 3.日历中可展示历史记录作为数据…...
【express-generator】08-路由重定向
前言 通过前面两篇文章的讲解,我们已经介绍完第二阶段的前两点,本篇介绍第三点:路由重定向。 1. 路由重定向概述 路由重定向是指在服务器端将客户端的请求从一个 URL 重定向到另一个 URL 的过程。这通常通过 HTTP 状态码(如 30…...
搭建Spring Boot开发环境
JDK(1.8及以上版本) Apache Maven 3.6.0 修改settings.xml 设置本地仓库位置 <localRepository>D:/repository</localRepository> 设置远程仓库镜像 <mirror><id>alimaven</id><name>aliyun maven</name&…...
Spatial Group-wise Enhance (SGE) module
来源: [1905.09646] Spatial Group-wise Enhance: Improving Semantic Feature Learning in Convolutional Networks 相关工作: #GroupedFeatures #AttentionModels 创新点: 贡献: 提出了一种轻量级的SGE模块,能够…...
二叉搜索树中的搜索(力扣700)
首先介绍一下什么是二叉搜索树。 二叉搜索树是一个有序树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;它的左、右子树也分别为二叉…...
记录让cursor帮我给ruoyi-vue后台管理项目整合mybatis-plus
自己整合过程中会出现 work.web.exception.GlobalExceptionHandler :100 | 请求地址/admin/device/install/detail/1,发生未知异常. org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.fire.mapper.DeviceInstallMapper.selectById at o…...
【可实战】Linux 系统扫盲、 Shell扫盲(如何写一个简单的shell脚本)
一、Linux系统扫盲 1.Linux 能运行主要的 UNIX 工具软件、应用程序和网络协议 2.Linux 的发行版说简单点就是将 Linux 内核与应用软件做一个打包。 目前市面上较知名的发行版有:Ubuntu、RedHat、CentOS、Debian、Fedora、SuSE、OpenSUSE、Arch Linux、SolusOS 等…...
sqlzoo答案4:SELECT within SELECT Tutorial
sql练习:SELECT within SELECT Tutorial - SQLZoo world表: namecontinentareapopulationgdpAfghanistanAsia6522302550010020343000000AlbaniaEurope28748283174112960000000AlgeriaAfrica238174137100000188681000000AndorraEurope46878115371200000…...
【fly-iot飞凡物联】(20):2025年总体规划,把物联网整套技术方案和实现并落地,完成项目开发和课程录制。
前言 fly-iot飞凡物联专栏: https://blog.csdn.net/freewebsys/category_12219758.html 1,开源项目地址进行项目开发 https://gitee.com/fly-iot/fly-iot-platform 完成项目开发,接口开发。 把相关内容总结成文档,并录制课程。…...
Lucene常用的字段类型lucene检索打分原理
在 Apache Lucene 中,Field 类是文档中存储数据的基础。不同类型的 Field 用于存储不同类型的数据(如文本、数字、二进制数据等)。以下是一些常用的 Field 类型及其底层存储结构: TextField: 用途:用于存储…...
适用于IntelliJ IDEA 2024.1.2部署Tomcat的完整方法,以及笔者踩的坑,避免高血压,保姆级教程
Tips:创建部署Tomcat直接跳转到四 一、软件准备 笔者用的是IntelliJ IDEA 2024.1.2和Tomcat 8.5。之前我使用的是Tomcat 10,但遇到了许多问题。其中一个主要问题是需要使用高于1.8版本的JDK,为此我下载了新的JDK版本,但这又引发了更多的兼容…...
XSS靶场通关详解
前言 这里作者采用phpstudy部署的xss-lab靶场,配置如下: 第一关 进入靶场后寻找页面的传参处,发现url中的name参数传了test给页面,可以在此处进行尝试xss 成功弹窗! payload: <script>alert(1)<…...
Excel 技巧15 - 在Excel中抠图头像,换背景色(★★)
本文讲了如何在Excel中抠图头像,换背景色。 1,如何在Excel中抠图头像,换背景色 大家都知道在PS中可以很容易抠图头像,换背景色,其实Excel中也可以抠简单的图,换背景色。 ※所用头像图片为百度搜索&#x…...
备忘-humanplus相关的代码解析
-1: numpy必须为1.20.0,否则会报错,版本冲突0.rlvalue-based: 如q-learning(走迷宫),对当前状态下作出的动作进行价值计算,通过贪婪策略穷尽所有可能选择最佳state-action,但是对于连续的动作空间&#x…...
青少年编程与数学 02-008 Pyhon语言编程基础 01课题、语言概要
青少年编程与数学 02-008 Pyhon语言编程基础 01课题、语言概要 一、榜一大哥起源与早期发展版本演进与社区壮大应用领域的拓展编程语言排行榜的常客结语 二、当前排行三、出色表现四、易学易用五、特色显著六、资源丰富初学者资源中高级学习资源在线编程学习平台 课题摘要:本文…...
XSS (XSS)分类
XSS (XSS) 概要 XSS全称为Cross Site Scripting,为了和CSS分开简写为XSS,中文名为跨站脚本。该漏洞发生在用户端,是指在渲染过程中发生了不在预期过程中的JavaScript代码执行。XSS通常被用于获取Cookie、以受攻击者的…...
[Linux]el8安全配置faillock:登录失败达阈值自动锁定账户配置
前言 本篇文章的配置仅使用于el8版本的Linux,目前已在centos8、BCLinux8上验证成功,其他版本系统是否可行还得考查。 el8中管理用户登录失败锁定账户所用的模块是faillock.so,如果想要将配置应用与其他版本的Linux,建议确认Linux…...
深入解析DDR内存训练:从FLY BY布线到信号对齐
1. 为什么DDR内存需要训练? 当你按下电脑开机键的那一刻,主板上的DDR内存就开始了一段奇妙的"热身运动"。这个热身过程专业术语叫做内存训练(Memory Training),它是确保内存稳定运行的关键步骤。想象一下&a…...
AI驱动的 Vue3应用开发平台深入探究(十五):扩展与定制之自定义设置器与属性编辑器
自定义设置器与属性编辑器 自定义 Setter 和属性编辑器构成了 VTJ 可扩展属性配置系统的基础,使开发者能够为物料组件属性创建专门的输入控件。该系统提供了基于插件的架构,与设计器环境无缝集成,同时为属性编辑场景提供最大的灵活性。 架构…...
Qwen3-VL-8B场景应用:电商商品图自动描述生成,节省运营时间
Qwen3-VL-8B场景应用:电商商品图自动描述生成,节省运营时间 1. 电商运营的痛点与解决方案 在电商行业,商品详情页的描述文案直接影响转化率。传统模式下,运营人员需要手动为每张商品图撰写描述,这个过程耗时耗力且难…...
如何通过llm-colosseum实现LLM模型的创新高效评估
如何通过llm-colosseum实现LLM模型的创新高效评估 【免费下载链接】llm-colosseum Benchmark LLMs by fighting in Street Fighter 3! The new way to evaluate the quality of an LLM 项目地址: https://gitcode.com/GitHub_Trending/ll/llm-colosseum 在人工智能快速发…...
电脑卡顿的幕后真相:为什么你的内存总是不够用?
电脑卡顿的幕后真相:为什么你的内存总是不够用? 【免费下载链接】memreduct Lightweight real-time memory management application to monitor and clean system memory on your computer. 项目地址: https://gitcode.com/gh_mirrors/me/memreduct …...
不用标注数据!手把手教你用SAM 3和SegEarth-OV3搞定遥感图像分割(附避坑指南)
零标注实战:用SAM 3与SegEarth-OV3实现遥感图像智能分割 当你在处理城市违建排查任务时,面对海量航拍图却找不到足够标注数据;当突发自然灾害需要快速评估受损区域,但现有模型无法识别新型地物——这些正是遥感图像分析中最棘手的…...
springboot-vue基于web的同城医院陪诊服务预约系统设计与实现
目录技术选型与架构设计核心功能模块划分数据库设计要点关键接口示例安全与性能优化测试与部署项目里程碑计划项目技术支持源码获取详细视频演示 :文章底部获取博主联系方式!同行可合作技术选型与架构设计 后端技术栈 使用Spring Boot 2.7.x框架搭建RE…...
OpenClaw灾难恢复:Qwen3-32B-Chat配置备份与快速重建
OpenClaw灾难恢复:Qwen3-32B-Chat配置备份与快速重建 1. 为什么需要自动化备份策略 上周五凌晨三点,我的开发机突然宕机。硬盘故障导致OpenClaw所有配置和Qwen3-32B-Chat模型接入设置全部丢失——这个教训让我意识到:个人开发环境同样需要企…...
Flink学习笔记:窗口
简介 langchain中提供的chain链组件,能够帮助我门快速的实现各个组件的流水线式的调用,和模型的问答 Chain链的组成 根据查阅的资料,langchain的chain链结构如下: $$Input \rightarrow Prompt \rightarrow Model \rightarrow Outp…...
手把手教你用Gemini 3和MediaPipe,为你的网页添加“隔空操控”魔法(附完整代码)
从零构建手势操控3D粒子系统:MediaPipe与Three.js深度整合指南 当我们在科幻电影中看到主角挥挥手就能操控全息界面时,总会心生向往。如今,借助MediaPipe的手势识别能力和Three.js的3D渲染技术,开发者完全可以在网页中实现这种&qu…...
