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…...
3步突破显卡限制:如何让AMD/Intel显卡实现DLSS级画质?
3步突破显卡限制:如何让AMD/Intel显卡实现DLSS级画质? 【免费下载链接】OptiScaler OptiScaler bridges upscaling/frame gen across GPUs. Supports DLSS2/XeSS/FSR2 inputs, replaces native upscalers, enables FSR3 FG on non-FG titles. Supports N…...
工程仿真平台OpenRocket:从物理试验到数字孪生的技术跃迁
工程仿真平台OpenRocket:从物理试验到数字孪生的技术跃迁 【免费下载链接】openrocket Model-rocketry aerodynamics and trajectory simulation software 项目地址: https://gitcode.com/GitHub_Trending/op/openrocket 在现代工程设计领域,物理…...
卡证检测矫正模型中小企业降本:替代万元级专用证件扫描仪方案
卡证检测矫正模型:中小企业降本利器,替代万元级专用证件扫描仪方案 1. 引言:一个被忽视的降本痛点 如果你在中小企业负责行政、人事或财务,一定对下面这个场景不陌生:每天要处理一堆身份证、护照、驾照的复印件或扫描…...
Axure 9.0 原生组件:绘制折线图
引言在原型设计中,数据可视化是传递核心信息的关键手段,而折线图凭借 “清晰展示数据趋势” 的优势,广泛应用于销售波动、用户增长、指标变化等场景。Axure 9.0 作为主流原型工具,虽未内置现成折线图组件,但通过「形状…...
告别软件盗版烦恼:用YT88加密狗5分钟搞定C#/Java/Python源代码加密(附完整开发包下载)
5分钟实现多语言源代码加密:YT88加密狗实战指南 独立开发者最头疼的问题之一,就是辛苦编写的代码被轻易反编译或盗用。上周我的一个朋友就遇到了这种情况——他花了三个月开发的Python数据分析工具,刚上线两周就被破解并免费传播。这种经历在…...
半导体制造中的ProcessJob与Control Job:从定义到实战避坑指南
半导体制造中的ProcessJob与Control Job:从定义到实战避坑指南 在半导体制造的高精度世界里,每一片晶圆的流转都像一场精密编排的交响乐。而ProcessJob(PJ)和Control Job(CJ)就是这场演奏中不可或缺的指挥…...
Scarab:重构空洞骑士模组管理体验的技术实践
Scarab:重构空洞骑士模组管理体验的技术实践 【免费下载链接】Scarab An installer for Hollow Knight mods written in Avalonia. 项目地址: https://gitcode.com/gh_mirrors/sc/Scarab 问题溯源:模组管理的隐性成本与技术瓶颈 量化手动管理的效…...
Linux系统管理必备:常用命令在Phi-3-vision模型部署与运维中的应用
Linux系统管理必备:常用命令在Phi-3-vision模型部署与运维中的应用 1. 前言:为什么需要掌握这些命令 部署和管理AI模型服务时,熟练使用Linux命令就像拥有了一把瑞士军刀。特别是对于Phi-3-vision这样的视觉大模型,从查看日志到监…...
共享图书借阅系统 Java 源码 + 数据库设计完整方案
以下是一个共享图书借阅系统的Java源码与数据库设计的完整方案,涵盖系统架构、核心功能实现、数据库设计以及安全防护措施等方面:一、系统架构技术栈:后端:Spring Boot 2.x MyBatis-Plus(简化数据库操作)前…...
foobar2000皮肤焕新:用foobox-cn打造沉浸式音乐体验
foobar2000皮肤焕新:用foobox-cn打造沉浸式音乐体验 【免费下载链接】foobox-cn DUI 配置 for foobar2000 项目地址: https://gitcode.com/GitHub_Trending/fo/foobox-cn 作为音乐爱好者,你是否也曾因foobar2000默认界面的单调乏味而却步…...
