当前位置: 首页 > news >正文

Spring:强制登陆与拦截器

1.只使用session验证

(1)第一步:用户登陆时存储session

@ApiOperation("用户登陆")
@PostMapping("/login")
public AppResult login(HttpServletRequest request,@RequestParam("username") @ApiParam("用户名") @NonNull String username,@RequestParam("password") @ApiParam("用户密码") @NonNull String password) {//1.参数校验 -- 注解已完成//2.调用service层User user = userService.login(username, password);//3.设置sessionHttpSession session = request.getSession(true);session.setAttribute(AppConfig.USER_SESSION,user);return AppResult.success();
}

关键代码:

HttpServletRequest request
 //3.设置sessionHttpSession session = request.getSession(true);session.setAttribute(AppConfig.USER_SESSION,user);//存储的是key-value

 

(2)第二步:访问接口时验获取session

@ApiOperation("查询用户信息")
@GetMapping("/info")
public AppResult<User> getUserInfo(HttpServletRequest request) {log.info("获取用户信息");User user = null;HttpSession session = request.getSession(false);if(session == null || session.getAttribute(AppConfig.USER_SESSION) == null) {//用户未登录return AppResult.failed(ResultCode.FAILED_FORBIDDEN);}user = (User) session.getAttribute(AppConfig.USER_SESSION);}if(user == null) {return AppResult.failed(ResultCode.FAILED_FORBIDDEN);}return AppResult.success(user);
}

关键代码:

HttpServletRequest request//参数
HttpSession session = request.getSession(false);
if(session == null || session.getAttribute(AppConfig.USER_SESSION) == null) {//用户未登录return AppResult.failed(ResultCode.FAILED_FORBIDDEN);
}

只要获取不到session或者不能从session中获取到对象,就说明用户没有登陆。 


上述就是只使用session进行强制用户登陆的写法,需要在每个方法都进行判断。 

2.使用拦截器强制登录和session

上述是没有引入拦截器的场景,每个部分都需要引入相同的代码,就会使得代码非常的繁琐,所以我们就可以使用Spring统一功能中的拦截器。

简单介绍拦截器:由两个部分组成

第一个部分:定义拦截器(也就是指定拦截规则,比如没有session就不允许访问);第二个部分:配置拦截器,也就是执行这些规则(比如把保安投放到某某路口等)

(1)第一步:定义拦截器

语法:实现HandlerInterceptor接口,并重写其所有方法

@Slf4j
@Component
public class LoginInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse    
response, Object handler) throws Exception {log.info("LoginInterceptor ⽬标⽅法执⾏前执⾏..");return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse
response, Object handler, ModelAndView modelAndView) throws Exception {log.info("LoginInterceptor ⽬标⽅法执⾏后执⾏");}@Overridepublic void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex) throws Exception {log.info("LoginInterceptor 视图渲染完毕后执⾏,最后执⾏");}
}

其中里面有三个重写的方法,一般我们只需要重写第一个就够了,就是我们需要的拦截器

(1)preHeandle:目标方法前执行该方法(比如执行获取用户信息的方法前,会先执行该方法)。该方法返回true,后面的方法继续执行(不拦截);返回false,后面的方法中断。

(2)postHandle:目标方法执行后就会执行该方法。

(3)afterCompletion:视图渲染完毕后执行,最后执行(后端开发现在几乎不涉及视图,暂不了解)

定义拦截器:基本模版

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;@Slf4j
//把对象交给Spring管理,否则不生效
@Component
public class LoginInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//1.获取sessionHttpSession session = request.getSession(false);//2.判断是否存在session或者用户已登录if(session != null && session.getAttribute("user") != null) {//进入该方法,说明用户已登录,就不进行拦截操作return true;}//3.走到这一步,说明用户未登录,进行拦截(也可以指定跳转某一个页面)response.sendRedirect("/login.html");//设置跳转的页面,一般为登陆页面return false;//拦截并跳转}
}

上面就是配置拦截器的基本代码模版,有一个注意点:跳转的页面最好是封装成一个常量,利于后续的修改操作。

(2)第二步:配置拦截器

上面的第一步我们已经定义好了拦截规则,下面只需要配置就好(上面已经规定了哪些人员不准进入小区,接下来我们需要投放保安到小区的指定路口进行拦截)

语法:WebMvcConfigurer接口,并重写addInterceptors方法

基本模版:

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 AppInterceptorConfigurer implements WebMvcConfigurer {@Autowiredprivate LoginInterceptor loginInterceptor;//给保安们注入拦截规则@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(loginInterceptor)//该方法是注册,也就是执行拦截规则.addPathPatterns("/**")//该方法表示拦截所有的请求.excludePathPatterns("/login");//表示该页面不进行拦截}
}

上面就是模版,一般登录页面和注册等页面我们都是不进行拦截的,要是拦截住了就死锁了。

然后对于要拦截什么页面,看大家的需求;对于拦截器+session的介绍就结束了,也就是上面的两段代码。

3.使用令牌拦截

使用令牌技术生成一个token字符串用来验证用户是否登陆

下面是关于用户登陆和验证的基本步骤: 

 (1)前端发送登陆请求,后端进行验证

(2)后端验证通过,返回token

(3)客户端存储token(通过前端进行操作)

(4)客户端后续发起的请求,就会把token放在请求的header中(k-v的形式,token存储在v中)

(5)后端从header中获取到token(指定前端的k,才能获取token),进行验证

这个部分前面先介绍如何在代码中使用登陆令牌,后面再介绍代码的含义

使用步骤大致分为四步:引入依赖、编写令牌工作类、发放令牌、验证令牌

(1)第一步:引入依赖

引入pom依赖,需要使用到令牌专属的类

<!--  jwt令牌  -->
<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-api -->
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-api</artifactId><version>0.11.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-impl -->
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-impl</artifactId><version>0.11.5</version><scope>runtime</scope>
</dependency>
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-jackson</artifactId><!-- or jjwt-gson if Gson is preferred --><version>0.11.5</version><scope>runtime</scope>
</dependency>

引入后记得刷新maven

(2)第二步:编写令牌工具utils

在主目录下创建utils包,再创建JwtUtils类

//负责生成令牌和验证令牌import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.JwtParser;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import lombok.extern.slf4j.Slf4j;import java.security.Key;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;@Slf4j
public class JwtUtils {private static long expiration =  30 * 60 * 1000;  //规定令牌有效期为30分钟private static String secretString = "gaiosfhioawjfajrawrawrawrawrawrawrawrfjarawrawrawrafawfoawjfa";private static Key key = Keys.hmacShaKeyFor(Decoders.BASE64.decode(secretString));//key值,数字签名/*** 生成令牌*/public static String genJwt(Map<String, Object> data) {//生产tokenString compact = Jwts.builder()//固定方法.setClaims(data)//设置数据.setExpiration(new Date(System.currentTimeMillis()+expiration))//设置token的过期时间.signWith(key)//设置数字签名.compact();//生产tokenreturn compact;}/*** 校验令牌*/public static Claims verify(String token){//生成token用的都是同一个key,所以不需要传参//获取build对象JwtParser build = Jwts.parserBuilder().setSigningKey(key).build();Claims claims = null;try {claims = build.parseClaimsJws(token).getBody();//与token校验}catch (ExpiredJwtException e){log.error("token过期, 校验失败, token:"+ token);}catch (Exception e){log.error("token校验失败, token:"+ token);}return claims;}}

作用:这个类提供两个静态方法,第一个是负责生成令牌,第二个是负责验证令牌。

上述的生成和验证令牌属于大致模版,自己也可以进行大致的修改

(3)第三步:后端发放令牌

一般在登陆接口给用户发放令牌。

@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {@RequestMapping("/login")public Result login(String userName, String password){//前面一堆验证工作,这里根据自己的业务功能写//………………UserInfo userInfo = new UserInfo();//账目密码验证完成,就可以给用户发放令牌了Map<String,Object> cliams = new HashMap<>();cliams.put("id", userInfo.getId());cliams.put("name", userInfo.getUserName());//获取对应的tokenString jwt = JwtUtils.genJwt(cliams);//返回tokenreturn Result.success(jwt);}
}

在验证完用户信息后,就可以给用户设置令牌并且返回token了,token中设置的信息一般不要设置隐私信息,比如用户密码

(4)第四步:后续验证令牌

这里直接采取统一拦截器进行拦截了,下面是关于拦截规则的代码

这一步作为纯后端程序猿来说比较困难,因为要和前端的参数进行同步。前端会把token(一个字符串)以k-v的形式放入header中,所以可以从请求中进行获取

@Slf4j
@Component
public class LoginInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//验证token是否合法String userToken = request.getHeader("user_token_header");log.info("从header中获取信息, token:"+ userToken);Claims claims = JwtUtils.verify(userToken);if (claims==null){//token校验失败response.setStatus(401);
//            response.getOutputStream().write();
//            response.setContentType();return false;}return true;}
}

user_token_header是请求头中的key,用来获取对应的value值,也就是token

相关文章:

Spring:强制登陆与拦截器

1.只使用session验证 &#xff08;1&#xff09;第一步&#xff1a;用户登陆时存储session ApiOperation("用户登陆") PostMapping("/login") public AppResult login(HttpServletRequest request,RequestParam("username") ApiParam("用…...

MySQL-数据库约束

1.约束类型 类型说明NOT NULL非空约束 指定非空约束的列不能存储NULL值 DEFAULT默认约束当没有给列赋值时使用的默认值UNIQUE唯一约束指定唯一约束的列每行数据必须有唯一的值PRIMARY KEY主键约束NOT NULL和UNIQUE的结合&#xff0c;可以指定一个列霍多个列&#xff0c;有助于…...

线性表三——队列queue

#include<bits/stdc.h> using namespace std; int n,m; queue<int> q;int main(){cin>>n>>m;for(int i1;i<n;i) q.push(i);int k0;while(!q.empty()){k;if(k<m)//从队头出来&#xff0c;再次回到队尾{int idq.front();//记录出去的编号 q.pop();…...

算法笔记(十)——队列+宽搜

文章目录 N 叉数的层序遍历二叉树的锯齿形层序遍历二叉树最大宽度在每个树行中找最大值 BFS是图上最基础、最重要的搜索算法之一&#xff1b; 每次都尝试访问同一层的节点如果同一层都访问完了&#xff0c;再访问下一层 BFS基本框架 void bfs(起始点) {将起始点放入队列中;标记…...

webpack配置全面讲解【完整篇】

文章目录 前言webpack 核心包&#xff1a;配置文件导出三种方式&#xff1a;在线配置 webpack配置文件解析&#xff1a;入口&#xff08;Entry&#xff09;&#xff1a;输出&#xff08;Output&#xff09;&#xff1a;加载器&#xff08;Loaders&#xff09;&#xff1a;插件&…...

十、kotlin的协程

协程 基本概念定义组成挂起和恢复结构化并发协程构建器作用域构建器挂起函数阻塞与非阻塞runBlocking全局协程像守护线程 Job的生命周期 常用函数延时和等待启动和取消启动取消 暂停 协程启动调度器启动方式启动模式线程上下文继承的定义继承的公式 协程取消与超时取消挂起点取…...

vscode qt 最新开发环境配置, 基于最新插件 Qt All Extensions Pack

qt 之前发布了vscode qt offical ,但是最新更新中将其升级改为了几个不同的插件&#xff0c;功能更强大 1. 前置条件 qt 已安装 2. 插件安装 打开vscode 插件安装&#xff0c;搜索qt 会看到很多qt插件&#xff0c;直接选择Qt All Extensions Pack 安装 会安装qt环境所需的…...

【MySQL】Ubuntu环境下MySQL的安装与卸载

目录 1.MYSQL的安装 2.MySQL的登录 3.MYSQL的卸载 4.设置配置文件 1.MYSQL的安装 首先我们要看看我们环境里面有没有已经安装好的MySQL 我们发现是默认是没有的。 我们还可以通过下面这个命令来确认有没有mysql的安装包 首先我们得知道我们当前的系统版本是什么 lsb_…...

C# StringBuilder类:高效构建和修改字符串的利器

C# 中的 StringBuilder 类是一个可变的字符序列&#xff0c;用于高效地构建和修改字符串。与字符串&#xff08;string&#xff09;不同&#xff0c;字符串在 C# 中是不可变的&#xff0c;这意味着每次修改字符串&#xff08;如拼接、替换等操作&#xff09;时&#xff0c;都会…...

AVL平衡树(AVL Tree)

**场景&#xff1a;课堂讨论** --- **小明&#xff08;ESFP学生&#xff09;**&#xff1a;张老师&#xff0c;为什么AVL树&#xff08;AVL Tree&#xff09;中的旋转操作这么重要&#xff1f;感觉只是节点的移动&#xff0c;有没有什么实际意义&#xff1f; **张老师&#…...

【python实操】python小程序之两数取大值以及login登录

引言 python小程序之两数取大值以及login登录 文章目录 引言一、两数取大值1.1 题目1.2 代码1.3 代码解释 二、login登录2.1 题目2.2 代码2.3 代码解释 三、思考3.1 两数取大值3.2 login登录 一、两数取大值 1.1 题目 定义一个函数my_max&#xff0c;包含两个参数, 函数的作用…...

Pikachu-File Inclusion-远程文件包含

远程文件包含漏洞 是指能够包含远程服务器上的文件并执行。由于远程服务器的文件是我们可控的&#xff0c;因此漏洞一旦存在&#xff0c;危害性会很大。但远程文件包含漏洞的利用条件较为苛刻&#xff1b;因此&#xff0c;在web应用系统的功能设计上尽量不要让前端用户直接传变…...

TIM(Timer)定时器的原理

一、介绍 硬件定时器的工作原理基于时钟信号源提供稳定的时钟信号作为计时器的基准。计数器从预设值开始计数&#xff0c;每当时钟信号到达时计数器递增。当计数器达到预设值时&#xff0c;定时器会触发一个中断信号通知中断控制器处理相应的中断服务程序。在中断服务程序中&a…...

Microsoft Visual Studio有多油饼

#1 Microsoft Visual Studio C 2023&#xff1a; 必须安装在C盘 为啥&#xff1f; 安其他盘能亖啊&#xff1f; 真有病 #2 Microsoft Visual Studio C 2013&#xff1a; 每个硬盘必须都腾出至少8个G的空间 不是我安在这个盘不就是为了其他盘没空间吗&#xff1f; 合着…...

Golang | Leetcode Golang题解之第452题用最少数量的箭引爆气球

题目&#xff1a; 题解&#xff1a; func findMinArrowShots(points [][]int) int {if len(points) 0 {return 0}sort.Slice(points, func(i, j int) bool { return points[i][1] < points[j][1] })maxRight : points[0][1]ans : 1for _, p : range points {if p[0] > …...

Python 从入门到实战35(进程-multiprocessing模块)

我们的目标是&#xff1a;通过这一套资料学习下来&#xff0c;可以熟练掌握python基础&#xff0c;然后结合经典实例、实践相结合&#xff0c;使我们完全掌握python&#xff0c;并做到独立完成项目开发的能力。 上篇文章我们讨论了turtle库绘制图画操作的相关知识。今天学习一下…...

“米哈游悄然布局未来科技:入股星海图,共绘具身智能机器人新篇章“

米哈游悄然入股具身智能机器人公司:技术布局与未来展望 近日,米哈游阿尔戈科技有限公司宣布入股具身智能机器人公司星海图,这一消息在行业内引起了广泛关注。米哈游,这家以游戏开发而闻名的企业,近年来正逐步扩大其在人工智能和新兴科技领域的投资布局,此次入股星海图正是…...

基于spring boot的篮球论坛系统

作者&#xff1a;计算机搬砖家 开发技术&#xff1a;SpringBoot、php、Python、小程序、SSM、Vue、MySQL、JSP、ElementUI等&#xff0c;“文末源码”。 专栏推荐&#xff1a;SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;Java精选实战项…...

华夏ERP账号密码泄露漏洞

漏洞描述 华夏ERP账号密码泄露漏洞 漏洞复现 FOFA "jshERP-boot" POC IP/jshERP-boot/user/getAllList;.ico...

Android问题笔记五十:构建错误-AAPT2 aapt2-7.0.2-7396180-windows Daemon

Unity3D特效百例案例项目实战源码Android-Unity实战问题汇总游戏脚本-辅助自动化Android控件全解手册再战Android系列Scratch编程案例软考全系列Unity3D学习专栏蓝桥系列ChatGPT和AIGC &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分…...

利用ngx_stream_return_module构建简易 TCP/UDP 响应网关

一、模块概述 ngx_stream_return_module 提供了一个极简的指令&#xff1a; return <value>;在收到客户端连接后&#xff0c;立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量&#xff08;如 $time_iso8601、$remote_addr 等&#xff09;&a…...

【OSG学习笔记】Day 18: 碰撞检测与物理交互

物理引擎&#xff08;Physics Engine&#xff09; 物理引擎 是一种通过计算机模拟物理规律&#xff08;如力学、碰撞、重力、流体动力学等&#xff09;的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互&#xff0c;广泛应用于 游戏开发、动画制作、虚…...

23-Oracle 23 ai 区块链表(Blockchain Table)

小伙伴有没有在金融强合规的领域中遇见&#xff0c;必须要保持数据不可变&#xff0c;管理员都无法修改和留痕的要求。比如医疗的电子病历中&#xff0c;影像检查检验结果不可篡改行的&#xff0c;药品追溯过程中数据只可插入无法删除的特性需求&#xff1b;登录日志、修改日志…...

前端导出带有合并单元格的列表

// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略

本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装&#xff1b;只需暴露 19530&#xff08;gRPC&#xff09;与 9091&#xff08;HTTP/WebUI&#xff09;两个端口&#xff0c;即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...

土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等

&#x1f50d; 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术&#xff0c;可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势&#xff0c;还能有效评价重大生态工程…...

Rapidio门铃消息FIFO溢出机制

关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系&#xff0c;以下是深入解析&#xff1a; 门铃FIFO溢出的本质 在RapidIO系统中&#xff0c;门铃消息FIFO是硬件控制器内部的缓冲区&#xff0c;用于临时存储接收到的门铃消息&#xff08;Doorbell Message&#xff09;。…...

LeetCode - 199. 二叉树的右视图

题目 199. 二叉树的右视图 - 力扣&#xff08;LeetCode&#xff09; 思路 右视图是指从树的右侧看&#xff0c;对于每一层&#xff0c;只能看到该层最右边的节点。实现思路是&#xff1a; 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...

无人机侦测与反制技术的进展与应用

国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机&#xff08;无人驾驶飞行器&#xff0c;UAV&#xff09;技术的快速发展&#xff0c;其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统&#xff0c;无人机的“黑飞”&…...

手机平板能效生态设计指令EU 2023/1670标准解读

手机平板能效生态设计指令EU 2023/1670标准解读 以下是针对欧盟《手机和平板电脑生态设计法规》(EU) 2023/1670 的核心解读&#xff0c;综合法规核心要求、最新修正及企业合规要点&#xff1a; 一、法规背景与目标 生效与强制时间 发布于2023年8月31日&#xff08;OJ公报&…...