Springboot整合JWT
1. 应用场景
前后端分离项目保持登录状态。
问题:ajax请求如何跨域,将无法携带jsessionid,这样会导致服务器端的session不可用。如何解决?
后端:
登录接口在验证过用户密码后,将用户的身份信息转换成一个特殊格式的字符串(token),放入响应体(或响应头)。
前端:
浏览器收到登录成功响应后,保存该token在本地,当下次发送请求时,取出该token并携带在请求头(或请求体中)。
后端:
使用filter或者拦截器校验请求中的token是否有效,如果有效就代表用户已登录,放行。
2. 对于token的需求
(1) 可以自定义信息(用户身份、权限信息)
(2) 需要使得服务器端可以进行有效性校验(即token只能由服务器端颁发,不能由其他第三方伪造)
(3) 需要能设置有效期
3. JWT的数据结构
https://jwt.io/ 官网地址
(1)HEADER //头
(2)PAYLOAD //体
(3)SIGNATURE //签名
4. 生成JWT
HMACSHA256(
base64UrlEncode(header) + "." +base64UrlEncode(payload),
your-256-bit-secret
)
(1)计算header的base64编码
(2)计算payload的base64编码
(3)计算签名
5. 校验token是否合法
原理:重新计算token的sign,与token中的sign进行比对,一致则合法。
6. 校验token有效期
原理,在jwt的payload中加入过期日期,然后在校验token时检查是否过期
这是一个测试类需要导入Hutool工具类
package com.qf.fmall.jwt;import cn.hutool.jwt.JWT;import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.HashMap;public class TestJwt {public static final String secretkey="qfsyjava2302";public static void main(String[] args) throws UnsupportedEncodingException, InterruptedException {String token1 = createToken();//验证token的合法性
// String token="eyJoZWFkZXIwMSI6InRlc3QxMjMiLCJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJsdWZmeSIsImlhdCI6MTY5MzIwNjc2NiwicGhvbmUiOiIxMzg5OTk5ODg4OCIsInNleCI6MSwiYWdlIjoxOX0.UY3v3twt30GAN6iCOlTTZwA0YpwMBFDg3JyWgxp1_7U";Thread.sleep(3000);//使用hutool工具类校验Jwtboolean validate = JWT.of(token1)//把token字符串传入,用来构建jwt对象.setKey(secretkey.getBytes("utf-8"))//传入计算签名要使用的密钥
// .verify() 只验证token值,不验证时间.validate(3l);//校验jwt是否合法,本质上就是重算签名,并且比较签名是否一致。//这里的leeway是秒,就是在原本的设定的失效时间,容许容忍几秒System.out.println(validate);}public static String createToken() throws UnsupportedEncodingException {//利用hutool工具类生成JwtHashMap<String, Object> payloadMap = new HashMap<>();payloadMap.put("age",19);payloadMap.put("sex",1);payloadMap.put("phone","13899998888");HashMap<String, Object> headMap = new HashMap<>();headMap.put("header01","test123");String token = JWT.create().addHeaders(headMap) //放入自定义Jwt 头.setSubject("luffy")//在 jwt 的payload中放入 sub(代表用户身份信息).setExpiresAt(new Date(System.currentTimeMillis()+1000*3))// 在jwt的payload中放入 jwt 失效时间.setIssuedAt(new Date()) //在 jwt 的payload 中 放入 jwt的签发时间.addPayloads(payloadMap) // 在jwt 的payload 中放入其他自定义内容.setKey(secretkey.getBytes("utf-8")) //放入计算jwt 需要的密钥字符串.sign();System.out.println(token);return token;
}}
7. 开启shiro登录校验
1.用拦截器的方式实现
实现拦截器接口
package com.qf.fmall.interceptor;import cn.hutool.jwt.JWT;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;@Component
@Slf4j
public class JwtInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//0.判断如果是浏览器发送的Option 请求,直接放行String method = request.getMethod();if (method.equals("OPTIONS")){return true;}//1.获取 请求头中的 tokenString token= request.getHeader("token");//校验jwttokenif (token==null){log.info("没带token,拒绝访问");return false;}boolean validate = JWT.of(token).setKey("qfsyjava2302".getBytes("utf-8")).validate(0);return validate;}
}
注册拦截器
package com.qf.fmall.config;import com.qf.fmall.interceptor.JwtInterceptor;
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 IntercepterConfig implements WebMvcConfigurer {@AutowiredJwtInterceptor jwtInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(jwtInterceptor).addPathPatterns("/index/indeximg");}
}
2.整合shiro过滤器
1.前端登录方法
@GetMapping("/login")@CrossOriginpublic ResultVo login(@RequestParam("username") String username,@RequestParam("password") String password) throws JsonProcessingException {Subject subject = SecurityUtils.getSubject();UsernamePasswordToken token =new UsernamePasswordToken(username,password);try {subject.login(token);Users principal = (Users) subject.getPrincipal();//当用户登录成功之后,创建jwt//把principal---> jsonObjectMapper mapper = new ObjectMapper();//获取springboot内置的json转换对象String userjson = mapper.writeValueAsString(principal);String jwt = JWT.create().setSubject(userjson).setExpiresAt(new Date(System.currentTimeMillis() + 1000 * 60 * 30)).setIssuedAt(new Date()).setKey("qfsyjava2302".getBytes()).sign();return ResultVo.vo(10000,jwt,principal);} catch (AuthenticationException e) {e.printStackTrace();return ResultVo.vo(112300,"failed",null);}}
2.后端验证过滤器
package com.qf.fmall.filter;import cn.hutool.jwt.JWT;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.web.filter.AccessControlFilter;
import org.springframework.stereotype.Component;import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;@Component("jwt")
@Slf4j
public class JwtFilter extends AccessControlFilter {/*** 用于验证访问受保护的方法* @param servletRequest* @param servletResponse* @param o* @return* @throws Exception*/@Overrideprotected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object o) throws Exception {HttpServletRequest request = (HttpServletRequest) servletRequest;//0.判断如果是浏览器发送的Option 请求,直接放行String method = request.getMethod();if (method.equals("OPTIONS")){return true;}//1.获取 请求头中的 tokenString token= request.getHeader("token");//校验jwttokenif (token==null){log.info("没带token,拒绝访问");return false;}boolean validate = JWT.of(token).setKey("qfsyjava2302".getBytes("utf-8")).validate(0);return validate;}/*** onAccessDenied 方法是Shiro框架中的一个回调方法,当主体(用户)被拒绝访问特定资源时会被调用。该方法不返回布尔值。* 当主体尝试访问受保护的资源但权限不足或未认证时,Shiro会触发 onAccessDenied 方法。通常,它用于处理被拒绝访问的情况,例如将用户重定向到错误页面或返回错误消息。* 因此,说 onAccessDenied 方法返回 true 是没有意义的。该方法的目的是处理访问被拒绝的情况,而不是返回布尔值。* @param servletRequest* @param servletResponse* @return* @throws Exception*/@Overrideprotected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {return false;}
}
3.让请求走shiro过滤器
在ShiroConfig类下写
//配置Shiro过滤器链@Beanpublic ShiroFilterChainDefinition shiroFilterChainDefinition(){DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();chainDefinition.addPathDefinition("/user/login**","anon");chainDefinition.addPathDefinition("/user/regist**","anon");chainDefinition.addPathDefinition("/error","anon");//让/index/indeximg 由自定义的shiro filter 进行处理, "jwt" 这个值是IOC容器中filter的名字chainDefinition.addPathDefinition("/index/indeximg","jwt");
// chainDefinition.addPathDefinition("/**","authc");return chainDefinition;}
但是shiro不仅会在shiro过滤器链下注册此过滤器,还会在springmvc过滤器链上注册
所以我们,还要让springmvc上的过滤器链上的此过滤器失效
4.让全局过滤器链上的JwtFilter失效
package com.qf.fmall.config;import com.qf.fmall.filter.JwtFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** 注意,为了不让 自定义filter也被中注册到全局FitlterChain中,* 需要添加如下配置类*/
@Configuration
public class FilterConfig {@AutowiredJwtFilter jwtFilter;@Beanpublic FilterRegistrationBean<JwtFilter> jwtFilterFilterRegistrationBean(){FilterRegistrationBean<JwtFilter> registrationBean = new FilterRegistrationBean<>();//要注册的filter的对象registrationBean.setFilter(jwtFilter);//让当前filter不用注册到,全局过滤器链上registrationBean.setEnabled(false);return registrationBean;}}
相关文章:
Springboot整合JWT
1. 应用场景 前后端分离项目保持登录状态。 问题:ajax请求如何跨域,将无法携带jsessionid,这样会导致服务器端的session不可用。如何解决? 后端: 登录接口在验证过用户密码后,将用户的身份信息转换成…...
如何使用Python和正则表达式处理XML表单数据
在日常的Web开发中,处理表单数据是一个常见的任务。而XML是一种常用的数据格式,用于在不同的系统之间传递和存储数据。本文通过阐述一个技术问题并给出解答的方式,介绍如何使用Python和正则表达式处理XML表单数据。我们将探讨整体设计、编写思…...
LA@方阵相似@相似矩阵的性质
文章目录 相似矩阵引言相似矩阵定义相似变换相似变换矩阵相似矩阵的矩阵多项式和特征值相同推论:与对角阵相似的矩阵性质定理 相似矩阵性质相似矩阵的乘方性质相似矩阵和矩阵多项式相似对角阵 对角阵多项式的展开小结 相似矩阵 引言 对角阵是矩阵中最简单的一类矩阵 对角阵相…...
ZLMediaKit 各种推拉流
1 用ffmpeg 推音视频流 ./ffmpeg -f dshow -i video"HP Wide Vision HD Camera" -f dshow -i audio"麦克风阵列 (Realtek High Definition Audio)" -rtbufsize 100M -max_delay 100 -pix_fmt yuv420p -tune zerolatency -c:v libx264 -crf 18 -s 1280x720…...
行业追踪,2023-08-29
自动复盘 2023-08-29 凡所有相,皆是虚妄。若见诸相非相,即见如来。 k 线图是最好的老师,每天持续发布板块的rps排名,追踪板块,板块来开仓,板块去清仓,丢弃自以为是的想法,板块去留让…...
【简单】228. 汇总区间
原题链接:https://leetcode.cn/problems/summary-ranges/description/ 228. 汇总区间 给定一个 无重复元素 的 有序 整数数组 nums 。 返回 恰好覆盖数组中所有数字 的 最小有序 区间范围列表 。也就是说,nums 的每个元素都恰好被某个区间范围所覆盖&…...
Mysql高级语句
高级语句 1.按关键字排序 SELECT column1, column2, ... FROM table_name ORDER BY column1, column2, ... ASC|DESC ASC 是按照升序进行排序的,是默认的排序方式,即 ASC 可以省略。 SELECT 语句中如果没有指定具体的排序方式,则默认按 ASC…...
Python中 re.compile 函数的使用
前言 嗨喽,大家好呀~这里是爱看美女的茜茜呐 以下介绍在python的re模块中怎样应用正则表达式 👇 👇 👇 更多精彩机密、教程,尽在下方,赶紧点击了解吧~ python源码、视频教程、插件安装教程、资料我都准备…...
【分布式搜索引擎es】
文章目录 数据搜索DSL实现查询文档搜索结果处理 RestClient实现 elasticsearch最擅长的是 搜索和 数据分析。 数据搜索 DSL实现 查询文档 常见的查询类型包括: 查询所有:查询出所有数据,一般测试用。例如:match_all全文检索…...
单片机的ADC
如何理解ADC。ADC就是将模拟量转换成数字量的过程,就是转换为计算机所能存储的0和1序列,比如将模拟量转换为一个字节,所以这个字节的大小要能反应模拟量的大小,比如一个0-5V的电压测量量(外部输入电压最小0V,最大为5V&…...
如何把pdf文件合并?分享最新pdf合并方法
在所有文档格式中,pdf应该是最常用的,像产品介绍、商务合同、法律文书等等,这些都是pdf格式的。有时候出于工作需要,我们要把两份或者多份pdf文件合并在一起,那么问题来了,如何把pdf文件合并呢?小编最近发…...
笙默考试管理系统-MyExamTest----codemirror(11)
笙默考试管理系统-MyExamTest----codemirror(11) 目录 笙默考试管理系统-MyExamTest----codemirror(11) 一、 笙默考试管理系统-MyExamTest----codemirror 二、 笙默考试管理系统-MyExamTest----codemirror 三、 笙默考试管…...
Spring MVC 五 - Spring MVC的配置和DispatcherServlet初始化过程
今天的内容是SpringMVC的初始化过程,其实也就是DispatcherServilet的初始化过程。 Special Bean Types DispatcherServlet委托如下一些特殊的bean来处理请求、并渲染正确的返回。这些特殊的bean是Spring MVC框架管理的bean、按照Spring框架的约定处理相关请求&…...
Ramp 有点意思的题目
粗一看都不知道这个要干什么,这 B 装得不错。 IyEvdXNyL2Jpbi9lbnYgcHl0aG9uMwoKJycnCktlZXAgdXMgb3V0IG9mIGdvb2dsZSBzZWFyY2ggcmVzdWx0cy4uCgokIG9kIC1kIC9kZXYvdXJhbmRvbSB8IGhlYWQKMDAwMDAwMCAgICAgNjAyMTUgICAyODc3OCAgIDI5MjI3ICAgMjg1NDggICA2MjY4NiAgIDQ1MT…...
算法通关村14关 | 堆在数组中找第k大的元素应用
1. 在数组中找第k大元素 题目 LeetCode215:给定整数数组nums和整数k,请返回数组中第k个最大的元素, 思路 解题思路用三个,选择法,堆查找和快速排序。 我们选择用大堆小堆解决问题,“找最大用小堆ÿ…...
Unity 顶点vertices,uv,与图片贴图,与mesh
mesh就是组成3d物体的三角形们。 mesh由顶点组成的三角形组成,三角形的大小 并不 需要一样,由顶点之间的位置决定。 mesh可以是一个或者多个面。 贴图的原点在左下角,uv是贴图的坐标,数量和顶点数一样(不是100%确定…...
Shell编程之函数
目录 基本概念 自定义函数 系统函数 1.read 2.basename 3.dirname 基本概念 将一段代码组合封装在一起实现某个特定的功能或返回某个特定的值,然后给这段代码取个名字,也就是函数名,在需要实现某个特定功能的时候直接调用函数名即可。 函…...
10.物联网LWIP之TCP状态转变
一。TCP状态机 1.青粗线:理想TCP状态转变(服务器视角下) 2.虚线:被动TCP状态转变(服务器视角下) 3.细实线:不经常出现的TCP状态转变(类似于边界处理) 1.青粗线解释--》服…...
Img标签的src地址自动拼接本地域名(localhost:8080)导致图片不显示问题
摘要:做Vueelement ui项目的时候,发现使用element ui的upload上传图片时,不显示的问题。我项目的图片是上传到七牛云,长传成功后返回存储在七牛云中的地址。后面发现是因为返回的地址是外部地址,需要完整的URL…...
数据结构入门 — 栈
本文属于数据结构专栏文章,适合数据结构入门者学习,涵盖数据结构基础的知识和内容体系,文章在介绍数据结构时会配合上动图演示,方便初学者在学习数据结构时理解和学习,了解数据结构系列专栏点击下方链接。 博客主页&am…...
Python爬虫实战:研究MechanicalSoup库相关技术
一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...
云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?
大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...
Ubuntu系统下交叉编译openssl
一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...
Android15默认授权浮窗权限
我们经常有那种需求,客户需要定制的apk集成在ROM中,并且默认授予其【显示在其他应用的上层】权限,也就是我们常说的浮窗权限,那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...
Element Plus 表单(el-form)中关于正整数输入的校验规则
目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入(联动)2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...
GitFlow 工作模式(详解)
今天再学项目的过程中遇到使用gitflow模式管理代码,因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存,无论是github还是gittee,都是一种基于git去保存代码的形式,这样保存代码…...
多模态图像修复系统:基于深度学习的图片修复实现
多模态图像修复系统:基于深度学习的图片修复实现 1. 系统概述 本系统使用多模态大模型(Stable Diffusion Inpainting)实现图像修复功能,结合文本描述和图片输入,对指定区域进行内容修复。系统包含完整的数据处理、模型训练、推理部署流程。 import torch import numpy …...
pikachu靶场通关笔记19 SQL注入02-字符型注入(GET)
目录 一、SQL注入 二、字符型SQL注入 三、字符型注入与数字型注入 四、源码分析 五、渗透实战 1、渗透准备 2、SQL注入探测 (1)输入单引号 (2)万能注入语句 3、获取回显列orderby 4、获取数据库名database 5、获取表名…...
