当前位置: 首页 > news >正文

SpringBoot集成JWT token实现权限验证

JWT=JSON Web Token

1. JWT的组成

JWT==Header,Payload,Signature==>abc.def.xyz

地址:JSON Web Tokens - jwt.er

1.1 Header

Header:标头。

两个组成部分:令牌的类型(JWT)和所使用的签名算法,经过Base64 Url编码后形成的JWT的第一部分。

{"type":"JWT","alg":"HS256"
}

1.2 Payload

Payload---有效负载。存放用户自定义消息

注意点:是以明文的形式进行展示,以Base64进行编码。

{“sub":"123","name":"jon","admin":true
}

1.3 Signature

signature--签名。使用标头的算法和私钥对第一部分和第二部分进行加密,通过Base64 Url编码后形成JWT的第三部分。

var encodeString =base64UrlEncode(header)+"."+base64UrlEncode(payload);
var signature=HMACSHA356(encodeString,secret);

2.JWT的基本使用

1.导入pom JWT依

JDK1.8以下的加入JWT依赖即可

        <!--JWT--><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version></dependency>

JDK1.8以上的加上其他

        <!--JWT--><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version></dependency><dependency><groupId>javax.xml.bind</groupId><artifactId>jaxb-api</artifactId><version>2.3.0</version></dependency><dependency><groupId>com.sun.xml.bind</groupId><artifactId>jaxb-impl</artifactId><version>2.3.0</version></dependency><dependency><groupId>com.sun.xml.bind</groupId><artifactId>jaxb-core</artifactId><version>2.3.0</version></dependency>

2.创建JWT

    //毫秒private long time=1000*60*60*24;//签名private String signature="admin";/*JWT加密*/@Testpublic void jwt(){//构建JWT对象:Jwts.builder()JwtBuilder jwtBuilder = Jwts.builder();String jwtToken = jwtBuilder//header:头部.setHeaderParam("typ", "JWT").setHeaderParam("alg", "HS256")//payload:载荷.claim("username", "tom").claim("role", "admin").setSubject("admin-test")//有效时间===>一天=当前时间+24小时//获得当前的系统时间:System.currentTimeMillis().setExpiration(new Date(System.currentTimeMillis() + time))//设置id字段.setId(UUID.randomUUID().toString())//signature:签名//注意点:这个签名算法要与前面的算法一致//设置加密算法和签名.signWith(SignatureAlgorithm.HS256, signature)//将前面3个重要信息拼接起来,使用”."来连接.compact();System.out.println(jwtToken);}

3.验证JWT

    @Test/*验证JWT*/public void checkJwt(){String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6InRvbSIsInJvbGUiOiJhZG1pbiIsInN1YiI6ImFkbWluLXRlc3QiLCJleHAiOjE2OTM2MzgzMDMsImp0aSI6ImU5ZjY3ZjBhLWE0NTAtNGYzYy1hYTY3LTU3ZGMwOWRjMDM4ZCJ9.FxA5c91E2bk2KW1rdMo8jlmClXgn7r2mVSaXs19Qzzk";//Jwts.parser():解析JwtParser jwtParser = Jwts.parser();//验证该token是否符合JWT规则boolean result = Jwts.parser().isSigned(token);System.out.println(result);//true}

4.解析JWT

    @Test/*解析JWT*/public void parseJwt(){String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6InRvbSIsInJvbGUiOiJhZG1pbiIsInN1YiI6ImFkbWluLXRlc3QiLCJleHAiOjE2OTM2MzgzMDMsImp0aSI6ImU5ZjY3ZjBhLWE0NTAtNGYzYy1hYTY3LTU3ZGMwOWRjMDM4ZCJ9.FxA5c91E2bk2KW1rdMo8jlmClXgn7r2mVSaXs19Qzzk";//获取JWT的解析对象JwtParser jwtParser = Jwts.parser();//通过signature对token进行签名,解开//parseClaimsJws:将JWT转换为key-value的形式,通过key来获取对应的value//Jws<Claims>:类似于Map集合Jws<Claims> claimsJws = jwtParser.setSigningKey(signature).parseClaimsJws(token);//获取Jws对象中的数据:get(key)表示根据key来获取value//相当于将header和payload封装为一个claimsClaims claims = claimsJws.getBody();//存储的是用户保存的数据Object username = claims.get("username");System.out.println(username);Object role = claims.get("role");System.out.println(role);String id = claims.getId();System.out.println(id);//签名String subject = claims.getSubject();System.out.println(subject);//有效期Date time = claims.getExpiration();System.out.println(time);}

3.SpringBoot + vue +JWT

 1.导入pom JWT依

JDK1.8以下的加入JWT依赖即可

        <!--JWT--><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version></dependency>

JDK1.8以上的还要加上以下依赖

        <!--JWT--><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version></dependency><dependency><groupId>javax.xml.bind</groupId><artifactId>jaxb-api</artifactId><version>2.3.0</version></dependency><dependency><groupId>com.sun.xml.bind</groupId><artifactId>jaxb-impl</artifactId><version>2.3.0</version></dependency><dependency><groupId>com.sun.xml.bind</groupId><artifactId>jaxb-core</artifactId><version>2.3.0</version></dependency><dependency><groupId>javax.activation</groupId><artifactId>activation</artifactId><version>1.1.1</version></dependency>

2.导入工具类

public class JwtUtil {//毫秒private static long time=1000*60*60*24;//签名private static String signature="admin";public static String createToken(){//构建JWT对象:Jwts.builder()JwtBuilder jwtBuilder = Jwts.builder();String jwtToken=jwtBuilder//header.setHeaderParam("typ", "JWT").setHeaderParam("alg", "HS256")//payload.claim("username", "admin").claim("role", "admin").setSubject("admin-test")//有效时间===>一天=当前时间+24小时//获得当前的系统时间:System.currentTimeMillis().setExpiration(new Date(System.currentTimeMillis()+time)).setId(UUID.randomUUID().toString())//signature//注意点:这个签名算法要与前面的算法一致.signWith(SignatureAlgorithm.HS256,signature)//将前面3个重要信息拼接起来.compact();return jwtToken;}
}

3.在后台解决跨域问题

@Configuration//配置类
public class CoreConfiguration implements WebMvcConfigurer {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**")//所有接口.allowCredentials(true)//是否发送Cookie.allowedOriginPatterns("*")//支持域.allowedMethods("GET","POST","PUT","DELETE")//支持方法.allowedHeaders("*").exposedHeaders("*");}
}

4.前台登录界面

5.前端代码

  methods:{handleSubmit(){this.$refs.ruleForm.validate((valid)=>{if(valid){let _this=thisaxios.get("http://localhost:8080/login",{param:_this.ruleForm}).then(function (response){console.log(response.data)})}})}}

6.进行路由跳转,并且将用户信息存到本地存储中

JSON.stringify-->将JSON转换为字符串

    handleSubmit(){this.$refs.ruleForm.validate((valid)=>{if(valid){let _this=thisaxios.get("http://localhost:8080/login",{param:_this.ruleForm})./*带着用户输入的用户名和密码*/then(function (response){console.log(response.data)//如果data不为空,则表示登录成功if(response.data!=null){//使用localStorage//将JSON转换为字符串localStorage.setItem('access-admin',JSON.stringify(response.data))//跳转到首页_this.$router.replace({path:"/"})}})}})}

7.将用户信息展示到页面中

JSON.parse--->将字符串转换为JSON

<template>
<div>欢迎回来:{{admin.username}}
</div>
</template>data(){return{admin:''}},created() {
//获取数据this.admin=JSON.parse(window.localStorage.getItem("access-admin"));},

8.添加验证用户信息是否存在【在路由中写】

/router/index.js

router.beforeEach((to,from,next)=>{if(to.path.startsWith('/login')){window.localStorage.removeItem('access-admin')next()}else {let admin=JSON.parse(window.localStorage.getItem('access-admin'))if(!admin){next({path:'/login'})}else {//校验token合法性axios({url:'http://localhost:8080/checkeToken',method:'get',headers:{token:admin.token}}).then((response)=>{if(!response.data){console.log("校验失败");next({path:'/error'})}})}}
})

9.后端验证Token方法

UserController

    /*** 验证token方法*/@GetMapping("/checkToken")public Boolean checkToken(HttpServletRequest request){//因为前端是将数据存储在header,所以我们要是有getHeaderString token = request.getHeader("token");return JwtUtil.checkToken(token);}

JwtUtil

    /*** 校验token是否正确*/public static boolean checkToken(String token){if (token==null){return false;}try {//解析Jws<Claims> claimsJws = Jwts.parser().setSigningKey(signature).parseClaimsJws(token);}catch (Exception e){e.printStackTrace();}return true;}

4.Springboot+JWT

User

@Data
public class User {private String username;private String password;private String token;
}

UserController:生成JWT令牌

public class UserController {private final String USERNAME = "admin";private final String PASSWORD = "123123";@GetMapping("/login")public User login(User user){//判断是否正确if(USERNAME.equals(user.getUsername()) && PASSWORD.equals(user.getPassword())){//添加token;token保存到user对象//定义一个工具类,将生成JWTuser.setToken(JwtUtil.createToken());return user;}return null;}
}

JwtUtil:生成JWT令牌

public class JwtUtil {//毫秒private static long time=1000*60*60*24;//签名private static String signature="admin";public static String createToken(){//构建JWT对象:Jwts.builder()JwtBuilder jwtBuilder = Jwts.builder();String jwtToken=jwtBuilder//header.setHeaderParam("typ", "JWT").setHeaderParam("alg", "HS256")//payload.claim("username", "admin").claim("role", "admin").setSubject("admin-test")//有效时间===>一天=当前时间+24小时//获得当前的系统时间:System.currentTimeMillis().setExpiration(new Date(System.currentTimeMillis()+time)).setId(UUID.randomUUID().toString())//signature//注意点:这个签名算法要与前面的算法一致.signWith(SignatureAlgorithm.HS256,signature)//将前面3个重要信息拼接起来.compact();return jwtToken;}
}

【前端直接传递token】

JwtUtil:验证JWT是否过期

    /*** 校验token是否过期*/public static boolean checkToken(String token){if (token==null || token==""){return false;//false表示令牌过期}try {//拿到JWT对象Jws<Claims> claimsJws = Jwts.parser().setSigningKey(signature).parseClaimsJws(token);}catch (Exception e){e.printStackTrace();}return true;}

UserController:验证JWT是否过期

    /*** 验证token是否过期:前端传递token*/@GetMapping("/checkToken")public Boolean checkToken(String token){return JwtUtil.checkToken(token);}

【将Token放入请求头中,使用request】

 JwtUtil:验证JWT是否过期

    /*** 校验token是否过期*/public static boolean checkToken(String token){if (token==null || token==""){return false;//false表示令牌过期}try {//拿到JWT对象Jws<Claims> claimsJws = Jwts.parser().setSigningKey(signature).parseClaimsJws(token);}catch (Exception e){e.printStackTrace();}return true;}

UserController:验证JWT是否过期

    /*** 验证token是否过期:前端将数据封装在请求头中* @param request* @return*/public boolean checkToken(HttpServletRequest request){//getHeader中的key要与前端通过一致String token = request.getHeader("token");//key-->tokenreturn JwtUtil.checkToken(token);}

解决跨域问题

参考:SpringBoot跨域请求的问题_m0_63077733的博客-CSDN博客

@Configuration
public class CorsConfig implements WebMvcConfigurer {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**") // 所有接口.allowCredentials(true) // 是否发送 Cookie.allowedOriginPatterns("*") // 支持域.allowedMethods("GET", "POST", "PUT", "DELETE") // 支持方法.allowedHeaders("*").exposedHeaders("*");}
}

拦截器实现Token验证

@Configuration
public class TokenInterceptor implements HandlerInterceptor {//在请求处理方法被调用之前被调用@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//前提:token放在请求头中String token = request.getHeader("token");if (!JwtUtil.checkToken(token)) {return false;//验证失败}return true;}
}

相关文章:

SpringBoot集成JWT token实现权限验证

JWTJSON Web Token 1. JWT的组成 JWTHeader,Payload,Signature>abc.def.xyz 地址&#xff1a;JSON Web Tokens - jwt.er 1.1 Header Header:标头。 两个组成部分&#xff1a;令牌的类型&#xff08;JWT&#xff09;和所使用的签名算法&#xff0c;经过Base64 Url编码后形成…...

算法通关村第11关【青铜】| 位运算基础

1.数字在计算机中的表示 原码、反码和补码都是计算机中用于表示有符号整数的方式。它们的使用旨在解决计算机硬件中的溢出和算术运算问题。 原码&#xff08;Sign-Magnitude&#xff09;&#xff1a; 原码最简单&#xff0c;它的表示方式是用最高位表示符号位&#xff0c;0表示…...

无涯教程-Android - RadioGroup函数

RadioGroup类用于单选按钮集。 如果我们选中属于某个单选按钮组的一个单选按钮,它将自动取消选中同一组中以前选中的任何单选按钮。 RadioGroup属性 以下是与RadioGroup控制相关的重要属性。您可以查看Android官方文档以获取属性的完整列表以及可以在运行时更改这些属性的相关…...

降噪音频转录 Krisp: v1.40.7 Crack

主打人工智能降噪服务的初创公司「Krisp」近期宣布推出音频转录功能&#xff0c;能对电话和视频会议进行实时设备转录。该软件还整合的ChatGPT&#xff0c;以便快速总结内容&#xff0c;开放测试版于今天上线。 随着线上会议越来越频繁&#xff0c;会议转录已成为团队工作的重…...

基于React实现:弹窗组件与Promise的有机结合

背景 弹窗在现代应用中是最为常见的一种展示信息的形式&#xff0c;二次确认弹窗是其中最为经典的一种。当我们在React&#xff0c;Vue这种数据驱动视图的前端框架中渲染弹窗基本是固定的使用形式。 使用方式&#xff1a;创建新的弹窗组件&#xff0c;在需要弹窗的地方引用并…...

docker使用(一)生成,启动,更新(容器暂停,删除,再生成)

docker使用&#xff08;一&#xff09; 编写一个 Dockerfile构建镜像构建失败构建成功 运行镜像运行成功 修改代码后再次构建请不要直接进行构建&#xff0c;要将原有的旧容器删除或暂停停止成功删除成功再次构建且构建成功&#xff01; 要创建一个镜像&#xff0c;你可以按照以…...

用Qt自制一个小闹钟

小闹钟 功能 当按下启动按钮时&#xff0c;停止按钮可用&#xff0c;启动按钮不可用&#xff0c;闹钟无法设置&#xff0c;无法输入自定义内容 当按下停止按钮时&#xff0c;暂停播报&#xff0c;启动按钮可用&#xff0c;闹钟可以设置&#xff0c;可以输入自定义内容 .pro文…...

Vue2.0/Vue3.0使用xlsx+xlsx-style实现导出Excel文件

一、依赖导入 1、Vue2 Webpack构建的 npm i xlsx npm i xlsx-style npm i file-saver同时修改以下&#xff1a; 解决 Can’t resolve ‘./cptable’ in ‘…’ 的问题&#xff0c;在 vue.config.js 文件中加入该配置 module.exports {externals: {./cptable: var cptable}…...

【Kafka系列】(一)Kafka入门

有的时候博客内容会有变动&#xff0c;首发博客是最新的&#xff0c;其他博客地址可能会未同步,认准https://blog.zysicyj.top 首发博客地址 系列文章地址 Kafka是什么&#xff1f; 一句话概括&#xff1a;「Apache Kafka 是一款开源的消息引擎系统」 什么是消息引擎系统&#…...

外包干了2个月,技术退步明显了...

先说一下自己的情况&#xff0c;大专生&#xff0c;19年通过校招进入湖南某软件公司&#xff0c;干了接近4年的功能测试&#xff0c;今年8月份&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测试…...

python实现语音识别

1. 首先安装依赖库 pip install playsound # 该库用于播放音频文件 pip install speech_recognition # 该库用于语音识别 pip install PocketSphinx # 语音识别模块中只有sphinx支持离线的&#xff0c;使用该模块需单独安装 pip install pyttsx3 # 该库用于将文本转换为语音播…...

java八股文面试[多线程]——线程的状态

5种状态一般是针对传统的线程状态来说&#xff08;操作系统层面&#xff09; 6种状态&#xff1a;Java中给线程准备的 NEW&#xff1a;Thread对象被创建出来了&#xff0c;但是还没有执行start方法。 RUNNABLE&#xff1a;Thread对象调用了start方法&#xff0c;就为RUNNABLE状…...

Go学习[合集]

文章目录 Go学习-Day1Go学习-Day2标识符变量基础语法字符串类型类型转换string和其他基本类型转换其他类型转stringstring转其他类型 指针类型运算符标准IO分支语句 Go学习-Day3循环语句函数声明init函数匿名函数闭包defer Go学习-Day4函数值传递&#xff0c;引用传递常用的函数…...

代码随想录算法训练营第42天 | ● 01背包问题,你该了解这些! ● 01背包问题,你该了解这些! 滚动数组 ● 416. 分割等和子集

文章目录 前言一、01背包问题&#xff0c;你该了解这些&#xff01;二、01背包问题&#xff0c;你该了解这些&#xff01; 滚动数组三、416. 分割等和子集总结 前言 01背包 一、01背包问题&#xff0c;你该了解这些&#xff01; 确定dp数组以及下标的含义 对于背包问题&#x…...

解决DNS服务器未响应错误的方法

​当你将设备连接到家庭网络或具有互联网接入功能的Wi-Fi热点时,由于各种原因,互联网连接可能无法正常工作。本文中的说明适用于Windows 10、Windows 8和Windows 7。 无法连接到DNS服务器的原因 故障的一类与域名系统有关,域名系统是世界各地互联网提供商使用的分布式名称…...

SpringBoot的HandlerInterceptor拦截器使用方法

一、创建拦截器 通过实现HandlerInterceptor接口创建自己要使用的拦截器 import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.…...

java 常用 jar 包

1 Lombok 是一个 java 类库&#xff0c;它利用注解方式自动生成 java bean 中 getter、setter、equals 等方法&#xff0c;还能自动生成 logger、toString、hashCode、builder 等 日志相关变量、Object 类方法或设计模式相关的方法&#xff0c;能够让你的 代码更简洁&#xff0…...

C#面试十问

1&#xff1a;C#中变量类型分为哪两种&#xff1f;它们的区别是什么&#xff1f;2&#xff1a;Class和Struct的区别&#xff1f;3&#xff1a;C#中类的修饰符和类成员的修饰符有哪些&#xff1f;4&#xff1a;面向对象的三个特征&#xff08;特点&#xff09;是什么&#xff1f…...

Day 41 动态规划part03 : 343. 整数拆分 96.不同的二叉搜索树

96. 不同的二叉搜索树 给你一个整数 n &#xff0c;求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种&#xff1f;返回满足题意的二叉搜索树的种数。 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;5示例 2&#xff1a; 输入&#xff1a;n 1…...

四轴飞行器的电池研究(MatlabSimulink仿真)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试

作者&#xff1a;Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位&#xff1a;中南大学地球科学与信息物理学院论文标题&#xff1a;BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接&#xff1a;https://arxiv.…...

测试markdown--肇兴

day1&#xff1a; 1、去程&#xff1a;7:04 --11:32高铁 高铁右转上售票大厅2楼&#xff0c;穿过候车厅下一楼&#xff0c;上大巴车 &#xffe5;10/人 **2、到达&#xff1a;**12点多到达寨子&#xff0c;买门票&#xff0c;美团/抖音&#xff1a;&#xffe5;78人 3、中饭&a…...

爬虫基础学习day2

# 爬虫设计领域 工商&#xff1a;企查查、天眼查短视频&#xff1a;抖音、快手、西瓜 ---> 飞瓜电商&#xff1a;京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空&#xff1a;抓取所有航空公司价格 ---> 去哪儿自媒体&#xff1a;采集自媒体数据进…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)

Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败&#xff0c;具体原因是客户端发送了密码认证请求&#xff0c;但Redis服务器未设置密码 1.为Redis设置密码&#xff08;匹配客户端配置&#xff09; 步骤&#xff1a; 1&#xff09;.修…...

使用 SymPy 进行向量和矩阵的高级操作

在科学计算和工程领域&#xff0c;向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能&#xff0c;能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作&#xff0c;并通过具体…...

docker 部署发现spring.profiles.active 问题

报错&#xff1a; org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...

人机融合智能 | “人智交互”跨学科新领域

本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...

Selenium常用函数介绍

目录 一&#xff0c;元素定位 1.1 cssSeector 1.2 xpath 二&#xff0c;操作测试对象 三&#xff0c;窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四&#xff0c;弹窗 五&#xff0c;等待 六&#xff0c;导航 七&#xff0c;文件上传 …...

快刀集(1): 一刀斩断视频片头广告

一刀流&#xff1a;用一个简单脚本&#xff0c;秒杀视频片头广告&#xff0c;还你清爽观影体验。 1. 引子 作为一个爱生活、爱学习、爱收藏高清资源的老码农&#xff0c;平时写代码之余看看电影、补补片&#xff0c;是再正常不过的事。 电影嘛&#xff0c;要沉浸&#xff0c;…...

探索Selenium:自动化测试的神奇钥匙

目录 一、Selenium 是什么1.1 定义与概念1.2 发展历程1.3 功能概述 二、Selenium 工作原理剖析2.1 架构组成2.2 工作流程2.3 通信机制 三、Selenium 的优势3.1 跨浏览器与平台支持3.2 丰富的语言支持3.3 强大的社区支持 四、Selenium 的应用场景4.1 Web 应用自动化测试4.2 数据…...