JWT代码实现

news2024/11/18 21:51:43

什么是 JWT?

JSON Web Token,通过数字签名的方式,以 JSON 对象为载体,在不同的服务终端之间安全的传输信 息。(将信息进行封装,以 JSON 的形式传递) JWT 有什么用? JWT 最常见的场景就是授权认证,一旦用户登录,后续每个请求都将包含 JWT,系统在每次处理用户请 求的之前,都要先进行 JWT 安全校验,通过之后再进行处理。

前后端传输数据时,一般是使用 session 或是 cookie,但是都相对有自己的弊端,JWT 是利用 token 来对用户身份进行验证的方式,具体流程是前端使用用户名和密码来登录,服务器收到请求后验 证用户名和密码,验证成功后,服务器会签发一个 token ,将 token 返回给前端,前端将收到的 token 存储起来,在每次请求资源时都必须携带 token,服务器收到请求,会先验证 token 是否有效,验证成 功就给前端返回请求的数据。

优势

这种基于 token 的认证方式相对于传统的 session 认证方式更节约服务器资源,token 在服务端不需要 存储 session 信息,因为 token 自身包含了所有登录用户的信息,所有可以减轻服务端压力。

JWT 的组成 JWT 由 3 部分组成,用.拼接

eyJ0eXAiOiJqd3QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6InRvbSIsInJvbGUiOiJhZG1pbiI
sInN1YiI6ImFkbWluLXRlc3QiLCJleHAiOjE2NjU1NTAzNDIsImp0aSI6IjBiOWU3MmRmLTQ0NjQtNDV
kYy04ODMwLWU3NTJkMjg1OGQ0MCJ9.00-RQiPM_a9_0q03CrmcrOBMaLbcfWw85Mbc7xc4AtU

 这三部分分别是:

Header

包含token 类型和加密算法的名称

{
//类型
'typ': 'jwt',
//算法
'alg': 'HS256'
}

将信息进行base64编码(转码)

Payload //载荷(存储有效信息)

包含标准中注册的声明、公共的声明、私有的声明,其实就是信息安全的分类,存储主要的信息 同时也需要将信息进行base64编码(转码) 

{
"sub": '1234567890',
"name": 'john',
"amdin":true
}

Signature //签名

将转码后的 header 和 payload 用.进行拼接之后再用使用 HS256 进行加盐加密,就构成了 jwt 的第三 部分

其实就是由转码后的 header 和 payload 进行再次加密后的数据

//对转码后的 Header 和 Payload 用.进行拼接
var encodedString = base64UrlEncode(header) + "." + base64UrlEncode(payload);
//使用 HS256 进行加盐加密
var signature = HMACSHA256(encodedString, 'secret');

项目搭建

pom.xml

<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<!-- jdk1.8 以上要加-->
<!-- <dependency>-->
<!-- <groupId>javax.xml.bind</groupId>-->
<!-- <artifactId>jaxb-api</artifactId>-->
<!-- <version>2.3.1</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>4.0.1</version>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>javax.activation</groupId>-->
<!-- <artifactId>activation</artifactId>-->
<!-- <version>1.1</version>-->
<!-- </dependency>-->

测试加密/解密

如何使用 jwt

加密

在这里我们测试一下 jwt 的加密和解密过程来了解 jwt

首先使用 JwtBuilder 来创建 jwt 对象 ,根据三部分先加入 jwt 的 header,使用.setHeaderParam() 这里使用链式编程增加参数,再加入载荷 payload 使用 .claim() 方法 还可以加入主题和有效时间(一 天的有效时间 System.currentTimeMillis() + time),id 用了 UUID

定义全局签名信息用于解密,使用 .sigWith(算法,签名key) 加密,调用 .compact() 进行拼接

输出 JWT 数据

import io.jsonwebtoken.*;
import javafx.scene.chart.PieChart;
import sun.awt.SunHints;
import java.security.Key;
import java.security.KeyException;
import java.util.Date;
import java.util.UUID;
public class Test {
private long time = 1000*60*60*24;
private String signature = "amdin";//签名信息(解密)
@org.junit.Test
public void jwt(){
JwtBuilder jwtBuilder = Jwts.builder();//用来构建jwt对象
String jwtToken = jwtBuilder
//Header
.setHeaderParam("typ","jwt")
.setHeaderParam("alg","HS256")
//Payload
.claim("username","tom")
.claim("role","admin")
.setSubject("admin-test")//主题
.setExpiration(new Date(System.currentTimeMillis() + time))//有效
时间 当前时间+一天 24h
.setId(UUID.randomUUID().toString())
//Signature
.signWith(SignatureAlgorithm.HS256,signature)
.compact();//拼接三部分
System.out.println(jwtToken);
}
@org.junit.Test
public void parse(){
String token =
"eyJ0eXAiOiJqd3QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6InRvbSIsInJvbGUiOiJhZG1pbi
IsInN1YiI6ImFkbWluLXRlc3QiLCJleHAiOjE2NjU1NTAzNDIsImp0aSI6IjBiOWU3MmRmLTQ0NjQtND
VkYy04ODMwLWU3NTJkMjg1OGQ0MCJ9.00-RQiPM_a9_0q03CrmcrOBMaLbcfWw85Mbc7xc4AtU";
JwtParser jwtParser = Jwts.parser();
//解密 通过签名进行解析
Jws<Claims> claimsJws =
jwtParser.setSigningKey(signature).parseClaimsJws(token);
//把解析的数据存入对象中
Claims claims = claimsJws.getBody();
//从对象中取出数据
System.out.println(claims.get("username"));
System.out.println(claims.get("role"));
System.out.println(claims.getId()); //ID
System.out.println(claims.getSubject()); //签名
System.out.println(claims.getExpiration()); //有效期截至时间
}
}

对 token 进行解密

首先 使用 Jwts.parser() 对象的 .setSigningkey(签名key)解密 .parseClaimsJws(token)会把所有信息解 析成 Claims,Claims 相当于我们的各种数据,通过签名对 token 进行解析拿到 Claims ,调用 .getBody 方法把封装的数据放到 claims 对象当中,之后就可以使用 对象 .get 方法取出数据,从而将 jwttoken 中解析出我们的数据。

Spring boot + vue + Jwt

简单的小项目来了解 jwt 具体用法

作为java web中的一个令牌,就像之前测试加密时,用户在登录后,访问咱们的登录接口,登录接口判 断登录成功后把用户信息转为 jwtoken(jwt工具类,跟上面加密过程一样) 存入用户信息中,把整个 用户对象给到前端。

controller

@GetMapping("/login")
public User login(User user){
if (USERNAME.equals(user.getUsername()) &&
PASSWORD.equals(user.getPassword())){
//添加token
user.setToken(JwtUtil.createToken());
return user;
}
return null;
}

 JwtUtil

private static long time = 1000*60*60*24;
private static String signature = "amdin";
public static String createToken(){
JwtBuilder jwtBuilder = Jwts.builder();//用来构建jwt对象
String jwtToken = jwtBuilder
//Header
.setHeaderParam("typ","jwt")
.setHeaderParam("alg","HS256")
//Payload
.claim("username","admin")
.claim("role","admin")
.setSubject("admin-test")//签名
.setExpiration(new Date(System.currentTimeMillis() + time))//有效
时间 当前时间+一天 24h
.setId(UUID.randomUUID().toString())
//Signature
.signWith(SignatureAlgorithm.HS256,signature)
.compact();//拼接三部分
return jwtToken;
}

 前端拿到数据,从请求中拿到 JSON 进入 home 页面

this.$refs.loginForm.validate((valid) => {
if (valid) {
//点击登录后的一个入口
// alert('submit!');
//把全局this记录下来
let _this = this
//axios的get请求需要套{params:_this},需要把loginForm对象给到
后台
this.$axios.get('http://localhost:8080/login',
{params:_this.loginForm}).then(function (response) {
console.log(response.data)
//使用 localStorage 进行存储 access-admin(localStorage
只能存储字符串)
localStorage.setItem('accessadmin',JSON.stringify(response.data))//JSON.stringify JSON转字符串的方法
//去到登录成功的页面
_this.$router.replace({path:'/home'})
})
} else {
this.$message.error('请输入所有字段!');
return false;
}
});

 登录后在请求中拿到用户数据(保证安全性不显示)

 home页面,将 JSON 取出并还原存入全局变量 admin 中,就可以从 admin 中取出数据显示到页面上

 

 

created() {
this.admin = JSON.parse(window.localStorage.getItem('access-admin'))
}

登录成功后切换页面进行验证(因为每次跳转都需要向后台发请求,重复代码太多,把验证抽象出来, 实现代码复用,所以写到路由当中,每个页面的跳转都需要经过路由)俗称路由守卫,首先验证用户是 否登录,(取出 JSON 还原 判断)如果没有登录直接跳转到登录页面,接着检验token合法性,访问后 台/checkToken,把保存的 token 传到后台进行认证,后台返回布尔值,如果是 flase 提示校验失败跳 转到错误页面,正确直接往后运行

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:8081/checkToken',
method:'get',
headers:{
token:admin.token//类似?传参
}
}).then((response)=>{
console.log(response.data)
//给一个布尔值,如果是flase,提示校验失败,给到错误页面
if (!response.data){
console.log('校验失败')
next({path:'/error'})
}
})
next()
}
}
})

后台验证

从 headers 中获取前端给的 token,进入工具类中进行验证

controller

@GetMapping("/checkToken")
public Boolean checkToken(HttpServletRequest request){
//因为前端是存入 headers 中
String token = request.getHeader("token");
return JwtUtil.checkToken(token);
}

判断 token 是否为空,使用 Jwts.parser()方法,类似之前的解密 token ,解析签名 signature ,解析后 拿到集合 获取 JwtToken ,不需要拿出数据,只需要判断解析是否异常,如果解析异常说明 token 失 效,如果有异常返回 false,反之则返回 true,给到前端

JwtUtil

public static boolean checkToken(String token){
if (token == null){
return false;
}
try {
//判断token是否有效,如果解析异常说明token无效
Jws<Claims> claimsJws =
Jwts.parser().setSigningKey(signature).parseClaimsJws(token);
} catch (Exception e) {
return false;
}
return true;
}

 在前端 console.log(response.data) 中可以看出是否有效

 

 验证,改变 token 有效时间

private static long time = 1000*5;

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

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

相关文章

web3.0 爆红是炒作还是真有赚头?

前言 最近两年虽然疫情肆虐全球&#xff0c;虽然困得住人们的脚步&#xff0c;但是困不住科技的发展趋势&#xff0c;前有元宇宙&#xff0c;后有 web3.0&#xff0c;新的热点一个接着一个的出现&#xff0c;技术革新也是越来越快&#xff0c;之前只能在科幻电影、科幻小说中出…

SIFT算法

文章目录 1. SIFT算法简介1.1 SIFT特征检测步骤1.2 SIFT算法的特点 2. SIFT算法原理2.1 尺度空间2.1.1 多分辨率金字塔2.1.2 高斯金字塔2.1.3 高斯尺度空间&#xff08;使用不同的参数&#xff09; 2.2 DoG空间极值检测&#xff08;查找关键点&#xff09;2.3 删除不好的极值点…

二、Kafka生产与消费全流程

Kafka生产与消费全流程 Kafka是一款消息中间件&#xff0c;消息中间件本质就是收消息与发消息&#xff0c;所以这节课我们会从一条消息开始生产出发&#xff0c;去了解生产端的运行流程&#xff0c;然后简单的了解一下broker的存储流程&#xff0c;最后这条消息是如何被消费者…

JVM笔记(一)

走进JVM JVM相对于Java应用层的学习难度更大&#xff0c;**开篇推荐掌握的预备知识&#xff1a;**C/C(关键)、微机原理与接口技术、计算机组成原理、操作系统、数据结构与算法、编译原理&#xff08;不推荐刚学完JavaSE的同学学习&#xff09;&#xff0c;如果没有掌握推荐的一…

javac 无效的目标发行版: xx

一、检查系统JDK版本 java --version 如果不符合&#xff0c;重新配置系统环境。 二、检查IDEA设置 1、项目结构->项目->SDK和语言级别 2、 项目结构->模块->设置每一个模块的语言级别。 3、java编译器&#xff0c;模块预言级别。 三、检查pom文件 <!--Licens…

qt学习——基本使用、对象树、按钮、信号与槽

初识qt **qt****qt命名规范以及相关快捷键的使用****QPushButton****对象树****点击按钮关闭窗口****信号和槽****标准的信号和槽****自定义信号和槽****带参数的自定义信号和槽传参以及函数的二义性问题** qt qt命名规范以及相关快捷键的使用 优点:Qt相对于C&#xff0c;有一…

华为OD机试真题 JavaScript 实现【狼羊过河】【2022Q4 100分】,附详细解题思路

一、题目描述 一农夫带着m只羊&#xff0c;n只狼过河&#xff0c;农夫有一条可载x只狼/羊的船&#xff1b;农夫在时或者羊的数量大于狼时&#xff0c;狼不会攻击羊&#xff1b; 农夫在不损失羊的情况下&#xff0c;运输几次可以完成运输&#xff1f; 返程不计入次数。 二、…

Vue中如何进行表单联动与级联选择?

Vue中如何进行表单联动与级联选择&#xff1f; 表单联动和级联选择是Vue.js中常见的功能。表单联动是指在一个表单中&#xff0c;当某一个输入框的值发生变化时&#xff0c;其他输入框的值也会随之改变。级联选择是指在一个选择框中&#xff0c;当选择一个选项时&#xff0c;另…

领域建模之数据模型设计方法论 | 京东云技术团队

本文通过实际业务需求场景建模案例&#xff0c;为读者提供一种业务模型向数据模型设计的方法论&#xff0c;用于指导实际开发中如何进行业务模型向数据模型转化抽象&#xff0c;并对设计的数据模型可用性、扩展性提供了建议性思考。通过文章&#xff0c;读者可以收获到业务模型…

linux 漏洞升级、初次安装 mysql

文章目录 适用安装遇到问题 适用 1、为解决Mysql漏洞而需要离线升级mysql版本&#xff1b; 2、初次安装Mysql也可以参考本文&#xff1b; 安装 提示&#xff1a;首次安装可跳过第二步、第三步 一、查看CentOS7系统自带mariadb # 查看系统自带的Mariadb [rootiZ2ze3hm3gyjy…

最全Java锁详解:独享锁/共享锁+公平锁/非公平锁+乐观锁/悲观锁

乐观锁 VS 悲观锁 乐观锁与悲观锁是一种广义上的概念&#xff0c;体现了看待线程同步的不同角度&#xff0c;在Java和数据库中都有此概念对应的实际应用。 1.乐观锁 顾名思义&#xff0c;就是很乐观&#xff0c;每次去拿数据的时候都认为别人不会修改&#xff0c;所以不会上…

英语中-后置定语

一般说来&#xff0c;形容词放在所修饰名词的前面。单个的现在分词、过去分词以及动名词作定语&#xff0c;都是放在所修饰名词&#xff08;或代词&#xff09;的前面。这些称为前置定语。 例如&#xff1a; a red flower/ an interesting story&#xff0c;这里red, interes…

SaaS人力资源管理系统的Bug

SaaS人力资源管理系统的Bug Bug1【18】 这里我是直接把代码复制过来的&#xff0c;然后就有一个空白 这是因为它的代码有问题&#xff0c;原本的代码如下所示 <el-table-column fixed type"index" label"序号" width"50"></el-table-co…

ssm+java在线考试批改阅卷系统

本次学校在线考试系统的实现过程&#xff0c;它的开发使用B/S结构即浏览器和服务器结构框架&#xff0c;采用SSM框架技术&#xff0c;数据库使用了mysql数据库&#xff0c;页面设计采用了MVC框架&#xff0c;后端采用了SSM框架技术scrip等其他一些脚本语言&#xff0c;使用到在…

hash算法详解

散列算法&#xff08;Hash Algorithm&#xff09;&#xff0c;又称哈希算法&#xff0c;杂凑算法&#xff0c;是一种从任意文件中创造小的数字「指纹」的方法。与指纹一样&#xff0c;散列算法就是一种以较短的信息来保证文件唯一性的标志&#xff0c;这种标志与文件的每一个字…

Java中的动态链接VS操作系统动态链接

在操作系统OS中为了优化内存的使用会采用一种动态链接方式&#xff0c;一个文件想要在操作系统中运行必须经过编译、汇编译、链接、装载等步骤。可以参考Java程序是怎么跑起来的。本篇主要讲解Java栈帧中动态链接部分与操作系统的的动态链接的区别与联系 操纵系统为什么需要动态…

2023年欧洲科学院院士中的华人学者简介

近日&#xff0c;2023年欧洲科学院新当选欧洲科学院院士名单出炉&#xff0c;由于入选学者接受邀请及注册的时间进度不同&#xff0c;入选名单陆续公布&#xff08;截止目前已更新135位&#xff09;。本文知识人网小编仅介绍入选名单中华人学者的情况。 欧洲科学院(Academia Eu…

优化--分类树,我从2s优化到0.1s

1.前言 分类树查询功能&#xff0c;在各个业务系统中可以说随处可见&#xff0c;特别是在电商系统中。 但就是这样一个简单的分类树查询功能&#xff0c;我们却优化了5次。 到底是怎么回事呢&#xff1f; 2.背景 我们的网站使用了SpringBoot推荐的模板引擎&#xff1a;Thym…

TiDB x Catalyst丨秒级洞悉数据价值,TiDB 帮助“客户成功 SaaS 厂商”提升用户体验

导读 Catalyst 是一家总部位于纽约的 SaaS 创业公司&#xff0c;它提供了一个直观且灵活的客户成功平台&#xff08;Custom Success Platform&#xff09;&#xff0c;可帮助客户成功团队汇聚客户数据&#xff0c;洞悉客户健康状况&#xff0c;推动客户留存和业务增长。目前 C…

「网络编程」第一讲:初识网络_网络基础1

「前言」文章是关于网络编程方面的&#xff0c;今天内容大致是网络基础&#xff0c;讲解下面开始&#xff01; 「归属专栏」网络编程 「笔者」枫叶先生(fy) 「座右铭」前行路上修真我 「枫叶先生有点文青病」 「每篇一句」 青山不改&#xff0c;绿水长流 ——白居易 目录 一、…