SpringBoot:JWT+Interceptor 实现基本的登录验证

前置背景

Result类

package com.example.day724test.Dao;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;//统一响应结果
@NoArgsConstructor
@AllArgsConstructor
@Data
public class Result<T> {private Integer code;//业务状态码  0-成功  1-失败private String message;//提示信息private T data;//响应数据//快速返回操作成功响应结果(带响应数据)public static <E> Result<E> success(E data) {return new Result<>(0, "操作成功", data);}//快速返回操作成功响应结果public static Result success() {return new Result(0, "操作成功", null);}public static Result error(String message) {return new Result(1, message, null);}
}

Mapper:

Service:

Controler:

    @PostMapping("/login")public ResponseEntity<?> login(@RequestParam("username") String username, @RequestParam("password") String password) {try {SysUser user = userService.get_by_name(username);if (user == null || !user.getPassword().equals(password)) {return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("用户名或密码错误");}return ResponseEntity.ok().body(user);} catch (Exception e) {log.error("登录异常", e);return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("服务器内部错误");}}/*添加一个查看所有的用户的信息方法去验证token相关*/@GetMapping("/all")public ResponseEntity<?> getAllUser() {try {List<SysUser> users = userService.get_all();return ResponseEntity.ok().body(users);} catch (Exception e) {log.error("获取用户列表异常", e);return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("服务器内部错误");}}

测试一下是否成功:

login接口:

all接口:

测试成功:步入正题

JSON Web Tokens (JWT) 和拦截器实现登录验证的详细步骤:

. 用户登录
- 用户提交用户名和密码到服务器。
- 服务器验证用户凭证。
- 如果验证成功,服务器生成一个 JWT 并将其返回给客户端。

引入jwt依赖项:这里使用的是版本低一些的

创建JwtUtil类:

//接收业务数据,生成token并返回public static String genToken(Map<String, Object> claims) {return JWT.create().withClaim("claims", claims)//.withExpiresAt(new Date(System.currentTimeMillis() + 1000 * 60 * 60 )).withExpiresAt(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24 * 7)).sign(Algorithm.HMAC256(KEY));}//接收token,验证token,并返回业务数据public static Map<String, Object> parseToken(String token) {return JWT.require(Algorithm.HMAC256(KEY)).build().verify(token).getClaim("claims").asMap();}

测试一波:

生成token:

将生成的token复制准备验证:

 经过验证可以使用去usercontroller实现登录验证:

原来的登录代码:

@PostMapping("/login")public ResponseEntity<?> login(@RequestParam("username") String username, @RequestParam("password") String password) {try {SysUser user = userService.get_by_name(username);if (user == null || !user.getPassword().equals(password)) {return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("用户名或密码错误");}return ResponseEntity.ok().body(user);} catch (Exception e) {log.error("登录异常", e);return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("服务器内部错误");}}

导入JwtUtil包的token验证代码:

    @PostMapping("/login")public ResponseEntity<?> login(@RequestParam("username") String username, @RequestParam("password") String password) {try {SysUser user = userService.get_by_name(username);if (user == null || !user.getPassword().equals(password)) {return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("用户名或密码错误");}/*登录成功之后的方法内容*/Map<String,Object> claims=new HashMap<>();claims.put("username",user.getUsername());claims.put("password",user.getPassword());String token= JwtUtil.genToken(claims);log.info("登录成功, 用户名: {}", user.getUsername());return ResponseEntity.ok().body(token);/*在登录接口生成了token*//*其他的接口需要验证token*/} catch (Exception e) {log.error("登录异常", e);return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("服务器内部错误");}}

查看是否返回了我们所需要的token信息:

接下来使得其它的接口验证token:验证成功返回数据 否则错误

原来的/user/all:

    @GetMapping("/all")public ResponseEntity<?> getAllUser() {try {List<SysUser> users = userService.get_all();return ResponseEntity.ok().body(users);} catch (Exception e) {log.error("获取用户列表异常", e);return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("服务器内部错误");}}

现在的接受token验证登录信息:

   @GetMapping("/all")public Result<String> getAllUser(@RequestHeader("Authorization") String token, HttpServletRequest response){ //请求头中获取tokentry {Map<String, Object> claims = JwtUtil.parseToken(token);return Result.success("所有的文章数据");}catch (Exception e){return Result.error("未登录");}}
/*在请求头信息中获取token
*/

测试:没有加token的时候

显然在postman测试请求头里面没有携带token所以提示未登录

携带token之后:

请求成功:这便完成了基本的登录检验

但是如果有多个接口 开发大工程项目势必过于繁琐 ,那么我们就使用更加抽象性的方法:使用拦截器

拦截器原理:

拦截器(Interceptors)是一种设计模式,用于在请求到达目标之前或响应离开之后执行某些操作。这种模式在多种编程环境和技术栈中都有应用,包括但不限于HTTP客户端和服务端、数据库访问层、消息队列等。

### 拦截器的基本原理

1. **注册拦截器**:
   - 在应用程序启动时或者某个配置阶段,你需要注册一个或多个拦截器。
   - 每个拦截器通常定义了两个方法:一个用于处理请求前的操作,另一个用于处理响应后的操作。

2. **请求处理**:
   - 当一个请求被发送时,它会先经过一系列预先注册的拦截器。
   - 每个拦截器可以对请求进行一些预处理,比如修改请求头、添加日志记录、验证认证信息等。
   - 如果某个拦截器决定阻止请求继续前进,它可以终止请求流程。
   - 如果请求通过了所有的拦截器,则会被发送到最终的目标。

3. **响应处理**:
   - 当响应从目标返回时,它也会经过相同的拦截器链。
   - 每个拦截器可以对响应进行一些后处理,例如修改响应体、添加额外的响应头等。
   - 响应最终被传递给最初发起请求的代码。

### 应用场景示例

#### AngularJS / Angular

1. **注册拦截器**:
   - 在AngularJS中,你可以通过 `$httpProvider.interceptors` 注册HTTP拦截器。
   - 在Angular中,你可以使用 `HttpClientInterceptor` 类型来创建自定义拦截器。

2. **请求与响应处理**:
   - 当发出一个HTTP请求时,请求会经过所有的请求拦截器。
   - 当收到响应时,响应会经过所有的响应拦截器。

#### Axios

1. **注册拦截器**:
   - Axios 提供了一个简单的API来注册请求和响应拦截器。
   - 可以通过 `axios.interceptors.request.use` 和 `axios.interceptors.response.use` 来注册拦截器函数。

2. **请求与响应处理**:
   - 当请求被发送之前,会依次调用请求拦截器。
   - 当响应被接收到之后,会依次调用响应拦截器。

#### Spring Framework

1. **注册拦截器**:
   - 在Spring MVC中,你可以创建实现了 `HandlerInterceptor` 接口的类,并在配置文件中注册它们。
   - 这些拦截器可以用来处理请求前后的操作。

2. **请求与响应处理**:
   - 当一个请求到达控制器之前,会调用拦截器的 `preHandle` 方法。
   - 如果请求被允许继续,那么在控制器处理完请求后,会调用拦截器的 `postHandle` 方法。
   - 最后,在视图渲染完成后,会调用拦截器的 `afterCompletion` 方法。

### 总结

拦截器提供了一种灵活的方式来扩展应用程序的功能,而不需要直接修改核心逻辑。它们可以在不改变现有代码结构的情况下增加新的功能,例如日志记录、性能监控、认证和授权、错误处理等。拦截器的设计使得系统的模块化程度更高,更易于维护和扩展。

源自黑马程序员springboot讲解 讲的很清楚

具体实现:

  • 继承Interceptor接口,
  • 获取到请求头中的token,
  • 得到token就可以让其继续执行,否则返回false:不允许进行
package com.example.day724test.intercepor;import com.example.day724test.Utils.JwtUtil;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;@Component
public class LoginInterceptor implements HandlerInterceptor {public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 获取请求头中的tokenString token = request.getHeader("Authorization");// 判断token是否为空,如果为空表示未登录,返回登录页面try {Map<String, Object> claims = JwtUtil.parseToken(token);/*放行*/return true;}catch (Exception e){return false;/*不放行*/}}
}

此外,定义

WebConfig类选择性过滤掉login,register  这两种接口外的其它接口需要实现登录验证
package com.example.day724test.config;import com.example.day724test.intercepor.LoginInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Component
@Configuration
public class WebConfig implements WebMvcConfigurer {@Autowiredprivate LoginInterceptor loginInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {//登录接口和注册接口不拦截registry.addInterceptor(loginInterceptor).excludePathPatterns("/user/login","/user/register");}
}

修改原来的Controller逻辑:

   @GetMapping("/all")public Result<String> getAllUser(@RequestHeader("Authorization") String token, HttpServletRequest response){ //请求头中获取token
//       try {
//           Map<String, Object> claims = JwtUtil.parseToken(token);
//           return Result.success("所有的文章数据");
//       }catch (Exception e){
//           return Result.error("未登录");
//       }return Result.success("所有的文章数据,,,,,,,,,");}

来进行测试:

直接访问/user/all:

携带token之后:

请求成功:基本的登录验证已经完成

项目保存的gitee地址:gitee地址

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

Qt+OpenCascade开发笔记(一):occ的windows开发环境搭建(一):OpenCascade介绍、下载和安装过程

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/140604141 长沙红胖子Qt&#xff08;长沙创微智科&#xff09;博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV…

【数据结构】手把手教你单链表(c语言)(附源码)

&#x1f31f;&#x1f31f;作者主页&#xff1a;ephemerals__ &#x1f31f;&#x1f31f;所属专栏&#xff1a;数据结构 目录 前言 1.单链表的概念与结构 2.单链表的结构定义 3.单链表的实现 3.1 单链表的方法声明 3.2 单链表方法实现 3.2.1 打印链表 3.2.2 创建新…

机械学习—零基础学习日志(高数11——三角函数)

零基础为了学人工智能&#xff0c;真的开始复习高数 三角函数之所以比较困难&#xff0c;是因为过于抽象&#xff0c;距离生活太过遥远&#xff0c;这里搜集一些资料&#xff0c;帮助大家能加深对三角函数的理解。 三角函数作用——能测距离 三角函数从应用层&#xff0c;开…

C++ | Leetcode C++题解之第287题寻找重复数

题目&#xff1a; 题解&#xff1a; class Solution { public:int findDuplicate(vector<int>& nums) {int slow 0, fast 0;do {slow nums[slow];fast nums[nums[fast]];} while (slow ! fast);slow 0;while (slow ! fast) {slow nums[slow];fast nums[fast]…

RuoYi基于SpringBoot+Vue前后端分离的Java快速开发框架学习_2_登录

文章目录 一、登录1.生成验证码2.验证码作用1.大体流程2.代码层面(我们都是从前端开始看起) 一、登录 1.生成验证码 基本思路&#xff1a; 后端生成一个表达式&#xff0c;例如34?7,显而易见后面是答案截取出来题干和答案把题干11&#xff1f;变成图片&#xff0c;变成流&a…

【Qt】QLCDNumber和QProgressBar

目录 QLCDNumber 倒计时小程序 相关属性 QProgressBar 进度条小程序 相关设置 QLCDNumber QLCDNumber是Qt框架中用于显示数字或计数值的小部件。通常用于显示整数值&#xff0c;例如时钟、计时器、计数器等 常用属性 属性说明intValueQLCDNumber显示的初始值(int类型)va…

Python爬虫技术 第13节 HTML和CSS选择器

在爬虫技术中&#xff0c;解析和提取网页数据是核心部分。HTML 和 CSS 选择器被广泛用于定位网页中的特定元素。下面将详细介绍这些选择器如何在 Python 中使用&#xff0c;特别是在使用像 Beautiful Soup 或 Scrapy 这样的库时。 HTML 选择器 HTML 选择器基于 HTML 元素的属性…

uniapp手写滚动选择器

文章目录 效果展示HTML/Template部分&#xff1a;JavaScript部分&#xff1a;CSS部分&#xff1a;完整代码 没有符合项目要求的选择器 就手写了一个 效果展示 实现一个时间选择器的功能&#xff0c;可以选择小时和分钟&#xff1a; HTML/Template部分&#xff1a; <picker…

从食堂采购系统源码到成品:打造供应链采购管理平台实战详解

本篇文章&#xff0c;笔者将详细介绍如何从食堂采购系统的源码开始&#xff0c;逐步打造一个完备的供应链采购管理平台&#xff0c;帮助企业实现采购流程的智能化和高效化。 一、需求分析与规划 一般来说&#xff0c;食堂采购系统需要具备以下基本功能&#xff1a; 1.供应商…

【原创】java+swing+mysql理发店管理系统设计与实现

个人主页&#xff1a;程序员杨工 个人简介&#xff1a;从事软件开发多年&#xff0c;前后端均有涉猎&#xff0c;具有丰富的开发经验 博客内容&#xff1a;全栈开发&#xff0c;分享Java、Python、Php、小程序、前后端、数据库经验和实战 开发背景&#xff1a; 随着社会经济的…

文件上传漏洞(ctfshow web151-161)

Web151 F12修改源代码 exts后面png改为php 这样就可以上传php的文件了 Web152&#xff1a; 考点&#xff1a;后端不能单一校验 就是要传图片格式&#xff0c;抓个包传个png的图片 然后bp抓包修改php后缀解析 然后放包 Web153-web156 在php代码中可以使用“{}”代替“[]” …

Nacos 高级详解:提升你的开发和部署效率

Nacos 高级 一 、服务集群 需求 服务提供者搭建集群 服务调用者&#xff0c;依次显示集群中各服务的信息 搭建 修改服务提供方的controller&#xff0c;打印服务端端口号 package com.czxy.controller;import org.springframework.web.bind.annotation.*;import javax.a…

Leetcode—240. 搜索二维矩阵 II【中等】

2024每日刷题&#xff08;149&#xff09; Leetcode—240. 搜索二维矩阵 II 实现代码 class Solution { public:bool searchMatrix(vector<vector<int>>& matrix, int target) {int r 0;int c matrix[0].size() - 1;while(r < matrix.size() &&…

magento2 安装win环境和linux环境

win10 安装 安装前提&#xff0c;php,mysql,apach 或nginx 提前安装好 并且要php配置文件里&#xff0c;php.ini 把错误打开 display_errorsOn开始安装 检查环境 填写数据库信息 和ssl信息&#xff0c;如果ssl信息没有&#xff0c;则可以忽略 填写域名和后台地址&#xff0…

【NLP自然语言处理】为什么说BERT是bidirectional

首先&#xff0c;来看一下Transformer架构图&#xff1a; 我们知道&#xff0c;Bert设计时主要采用的是Transformer编码器部分&#xff0c;要论述Bert为啥是双向的&#xff0c;我想从编码器和解码器的注意力机制来阐述。 在看这篇博客前&#xff0c;需要对Transformer有一定的…

vite构建vue3项目hmr生效问题踩坑记录

vite构建vue3项目hmr生效问题踩坑记录 hmr的好处 以下是以表格形式呈现的前端开发中HMR&#xff08;热模块替换&#xff09;带来的好处&#xff1a; 好处描述提升开发效率允许开发者在不刷新整个页面的情况下实时更新修改的代码&#xff0c;减少等待时间保持应用状态在模块替…

Vue3与Element-plus配合 直接修改表格中的一项数据——控制输入框的显示与隐藏

利用控制与隐藏输入框,直接修改表格中的每一项数据。 <!-- 表格模块 --> <div><el-table :data"tablelist" style"width: 100%"><el-table-column align"center" prop"deposit" label"接单押金">&l…

关于promise的一些例题(运行步骤详细说明)

关于promise的一些例题(详细说明) 基本例题 // 直接运行 输出 1 2 const promise new Promise((resolve, reject) > {console.log(1);resolve();console.log(2); });// then后面放入微队列 promise.then(() > {console.log(3); });// 输出4 之后没有代码了所以运行为队…

【运算放大器】输入失调电压和输入偏置电流(2)实例计算

概述 根据上一篇文章的理论&#xff0c;分别计算没有输入电阻和有输入电阻两种情况下的运放总输出误差。例题来自于TI高精度实验室系列课程。 目录 概述实例计算 1&#xff1a;没有输入电阻实例计算 2&#xff1a;有输入电阻总结 实例计算 1&#xff1a;没有输入电阻 要求&am…

Jmeter三种方式获取数组中多个数据并将其当做下个接口参数入参【附带JSON提取器和CSV格式化】

目录 一、传统方式-JOSN提取器获取接口返回值 1、接口调用获取返回值 2、添加JSON提取器 3、调试程序查看结果 4、添加循环控制器 5、设置count计数器 6、添加请求 7、执行请求 二、CSV参数化 1、将结果写入后置处理程序 2、设置循环处理器 3、添加CSV文件 4、设置…