当前位置: 首页 > 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;以及各种资源分…...

CAD 3dsmax maya等autodesk系列专用卸载修复工具AutoRemove,一键完全彻底卸载删除软件的专用卸载工具

AutoRemove 是一款功能强大的软件卸载工具&#xff0c;专门设计用于彻底清除Autodesk系列软件&#xff0c;如AutoCAD、3ds Max、Revit、Maya、Inventor、Navisworks、civil 3d、sketchbook、Architecture、Electrical、Mechanical、、等&#xff0c;从您的系统中。它通过深度清…...

python中的函数介绍

文章目录 1.函数1.1 语法格式1.2 函数参数1.3 函数的返回值1.4 变量作用域1.5 函数的执行过程1.6 链式调用1.7 嵌套调用1.8 函数栈帧1.9 函数递归1.10 参数默认值1.11 关键词参数 1.函数 无论是编程中的函数还是数学中的函数&#xff0c;本质都是差不多的&#xff0c;丢给函数…...

LinuxO(1)调度算法

概念 在Linux中&#xff0c;O(1)调度算法是一种进程调度算法。O(1)表示算法的时间复杂度是常数级别的&#xff0c;与系统中的进程数量无关。 运行队列结构 他采用了两个运行队列&#xff0c;一个活动队列和一个过期队列。活动队列中的进程是有资格获取CPU时间片的进程&#x…...

安防监控/视频系统EasyCVR视频汇聚平台如何过滤134段的告警通道?

视频汇聚/集中存储EasyCVR安防监控视频系统采用先进的网络传输技术&#xff0c;支持高清视频的接入和传输&#xff0c;能够满足大规模、高并发的远程监控需求。平台支持国标GB/T 28181协议、部标JT808、GA/T 1400协议、RTMP、RTSP/Onvif协议、海康Ehome、海康SDK、大华SDK、华为…...

SDKMAN!安装Maven

一、通过SDKMAN!正常安装 查看maven版本 sdk list maven安装maven 3.6.3版本 sdk install maven 3.6.3查看maven 3.6.3安装目录 sdk home maven 3.6.3安装过程中可能会失败&#xff0c;出现tmp临时目录中存在临时文件 # 移除临时文件&#xff0c;不要手动删除&#xff0c;…...

[NeurIPS 2022] STaR: Bootstrapping Reasoning With Reasoning

Contents IntroductionMethodExperimentsReferences Introduction CoT 推理可以有效提升 LLM 推理能力&#xff0c;但 few-shot prompting 无法发挥 CoT 的全部潜力&#xff0c;训练能够生成中间推理步骤 (i.e., rationale) 的 LLM 又需要大量人工标注 rationale&#xff0c;为…...

C++中对象的构造与析构

目录 一、引言 二、构造函数详解 1.构造函数的作用 2.构造函数的调用时机 3.构造函数的分类 三、析构函数详解 1.析构函数的作用 2.析构函数的调用时机 四、实例分析 五、总结 本文将详细讲解C中对象的构造和析构过程&#xff0c;包括构造函数、析构函数的作用及其调用时机…...

算法笔记(九)——栈

文章目录 删除字符串中的所有相邻重复项比较含退格的字符串基本计算机II字符串解码验证栈序列 栈是一种先进后出的数据结构&#xff0c;其操作主要有 进栈、压栈&#xff08;Push&#xff09; 出栈&#xff08;Pop&#xff09; 常见的使用栈的算法题 中缀转后缀逆波兰表达式求…...

动态SLAM总结一

文章目录 方法分类&#xff1a;OctoMap&#xff1a;&#xff08;2013&#xff09;UFOMap&#xff1a;&#xff08;2020&#xff09;Removert&#xff1a;&#xff08;2020&#xff09;ERASOR&#xff1a;&#xff08;2021&#xff09;DynamicFilter&#xff1a;&#xff08;202…...

HTB:Mongod[WriteUP]

连接至HTB服务器并启动靶机 靶机IP&#xff1a;10.129.99.33 分配IP&#xff1a;10.10.16.12 1.How many TCP ports are open on the machine? 使用nmap对靶机进行全端口TCP脚本、服务扫描&#xff1a; nmap -sC -sV -T4 -p- {TARGET_IP} 可以看到靶机共开放TCP端口2个&…...