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…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...
VB.net复制Ntag213卡写入UID
本示例使用的发卡器:https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...
3.3.1_1 检错编码(奇偶校验码)
从这节课开始,我们会探讨数据链路层的差错控制功能,差错控制功能的主要目标是要发现并且解决一个帧内部的位错误,我们需要使用特殊的编码技术去发现帧内部的位错误,当我们发现位错误之后,通常来说有两种解决方案。第一…...
Day131 | 灵神 | 回溯算法 | 子集型 子集
Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...
基础测试工具使用经验
背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...
【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分
一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计,提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合:各模块职责清晰,便于独立开发…...
JVM虚拟机:内存结构、垃圾回收、性能优化
1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...
GruntJS-前端自动化任务运行器从入门到实战
Grunt 完全指南:从入门到实战 一、Grunt 是什么? Grunt是一个基于 Node.js 的前端自动化任务运行器,主要用于自动化执行项目开发中重复性高的任务,例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...
无人机侦测与反制技术的进展与应用
国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机(无人驾驶飞行器,UAV)技术的快速发展,其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统,无人机的“黑飞”&…...
