JSON Web Token (JWT)的简单介绍、验证过程及令牌刷新思路

目录

一、JWT

1、什么是Jwt

2、为什么要使用Jwt

3、应用场景

4.Jwt的组成

4.1、Header

4.2、Payload

4.3、signature

二、Jwt验证过程

1、生成Jwt令牌

2、解析旧的Jwt

 3、复制Jwt

 4、Jwt有效时间测试

 三、Jwt令牌刷新思路

1、配置JwtFilter过滤器

2、登录生成Jwt令牌

3、配置CorsFilter过滤器

 4、Vuex存储Jwt令牌

5、修改main.js

6、配置axios请求响应头


 前言:        

          随着前后端分离的发展,以及数据中心的建立,越来越多的公司会创建一个中心服务器,服务于各种产品线。而这些产品线上的产品,它们可能有着各种终端设备,包括但不仅限于浏览器、桌面应用、移动端应用、平板应用、甚至智能家居。

这些设备与中心服务器之间会进行http通信,一般来说,中心服务器至少承担着认证和授权的功能。例如登录:各种设备发送消息到中心服务器,然后中心服务器响应一个身份令牌,当这种结构出现后,就出现一个问题:它们之间还能使用传统的cookie方式传递令牌信息吗?

其实,也是可以的,因为cookie在传输中无非是一个消息头而已,只不过浏览器对这个消息头有特殊处理罢了。但浏览器之外的设备肯定不喜欢cookie,因为浏览器有着对cookie完善的管理机制,但是在其他设备上,就需要开发者自己手动处理了。

JWT 的出现就是为了解决这个问题!!!

一、JWT

1、什么是Jwt

JSON Web Token (JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。是目前最流行的跨域身份验证解决方案;

RFC 7519:RFC 7519 - JSON Web Token (JWT)

2、为什么要使用Jwt

它要解决的问题,就是为多种终端设备,提供统一的、安全的令牌格式。因此,jwt只是一个令牌格式而已,你可以把它存储到cookie,也可以存储到localstorage,没有任何限制!同样的,对于传输,你可以使用任何传输方式来传输jwt,一般来说,我们会使用消息头header来传输它。

比如:当登录成功后,服务器可以给客户端响应一个Jwt。

HTTP/1.1 200 OK
...
set-cookie:token=jwt令牌
authorization:jwt令牌
...{..., token:jwt令牌}

 可以看到,jwt令牌可以出现在响应的任何一个地方,客户端和服务器自行约定即可。

当然,它也可以出现在响应的多个地方,比如为了充分利用浏览器的 cookie,同时为了照顾其他设备,也可以让 jwt 出现在 set-cookieauthorizationbody 中,尽管这会增加额外的传输量。

总之,Jwt的精髓在于去中心化,数据是保存在客户端的。

3、应用场景

  • 认证:认证是JWT的最常用场景。只要用户完成登录,其随后的请求都会包含JWT,以允许用户访问经由当前JWT授权的路由、服务或者是资源。由于开销小且能够被简单应用在跨域访问上,JWT在分布式站点上所支持的单点登录(SSO)已经是当前它被广泛应用的一个特性。
  • 信息交换:JWT是一种在各参与方之间安全传递信息的良好方法。由于JWT可以被签名(例:使用公钥/秘钥对),因而可用于确认发送者自称的身份。除此之外,由于signature使用headerpayload进行计算,也可以验证内容没有被篡改。

 JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。

4.Jwt的组成

 一个Jwt实际上就是一个字符串,它由三部分组成:

  • Header(头部)

  • Payload(载荷)

  • Signature(签名)

eyJhbGciOiJIUzI1NiJ9.
eyJzdWIiOiJ7fSIsImlzcyI6InpraW5nIiwiZXhwIjoxNTYyODUwMjM3LCJpYXQiOjE1NjI4NDg0MzcsImp0aSI6ImM5OWEyMzRmMDc4NzQyZWE4YjlmYThlYmYzY2VhNjBlIiwidXNlcm5hbWUiOiJ6c3MifQ.
WUfqhFTeGzUZCpCfz5eeEpBXBZ8-lYg1htp-t7wD3I4

 它是一个很长的字符串因此,中间用点(.)分隔成三个部分。

注意,Jwt 内部是没有换行的,这里只是为了便于展示,将它写成了几行。

4.1、Header

典型的JWT header包含两个部分:

  • typ(type)属性,用来标识整个token字符串是一个JWT字符串,即JWT。

  • alg(algorithm)属性,用来说明这个JWT签发的时候所使用的签名和摘要算法,比如HMAC  SHA256或者RSA

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

4.2、Payload

JWT token的第二部分是包含了声明的payload,声明(要求)是一个实体的表述加上额外信息,一共有三种形式的声明:注册、公有和私有;

  • 注册声明

它的json结构实际上是对JWT要传递的数据的一组声明,这些声明被JWT标准称为claims,它的一个属性值对其实就是一个claim(要求),每一个claim的都代表特定的含义和作用。

{"iss":"发行者","iat":"发布时间","exp":"到期时间","sub":"主题","aud":"听众","nbf":"在此之前不可用","jti":"JWT ID"
}
属性说明
iss(Issuser)代表这个JWT的签发主体
sub(Subject)代表这个JWT的主体,即它的所有人
aud(Audience)代表这个JWT的接收对象
exp(Expiration time)是一个时间戳,代表这个JWT的过期时间
nbf(Not Before)是一个时间戳,代表这个JWT生效的开始时间,意味着在这个时间之前验证JWT是会失败的
iat(Issued at)是一个时间戳,代表这个JWT的签发时间
jti(JWT ID)是JWT的唯一标识
  • 公有声明

公有声明可以加入任何信息,一般会添加用户相关信息或者业务需要的信息,但不建议添加敏感信息,因为该部分会在客户端解密。

  • 私有声明

私有声明是提供者和使用者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密,基本等同于明文信息。

如果把JWT用于认证, 那么JWT标准内规定的几个claim就足够用了,甚至只需要其中一两个就可以了,假如想往JWT里多存一些用户业务信息,比如角色和用户名等,这倒是可以用私有声明来添加。

4.3、signature

JWT的第三部分是签名信息,Signature由三部分组成:

  • header(base64加密后)

  • payload(base64加密后)

  • secret (盐)

签名需要将base64加密后的headerpayload使用.连接,然后通过header所使用的加密方式进行加盐(secret)组合加密,产生了jwt的第三部分。以使用HMAC SHA256算法为例;

按照前面alg可用值的说明,HS256其实包含的是两种算法:HMAC算法和SHA256算法,前者用于生成摘要,后者用于对摘要进行数字签名。这两个算法也可以用HMAC SHA256来统称;

HMACSHA256(base64UrlEncode(header) + "." +base64UrlEncode(payload),secret)

签名是用于验证消息在传递过程中有没有被更改,并且,对于使用私钥签名的token,它还可以验证JWT的发送方是否为它所称的发送方。  

算法不同,签名结果不同。

二、Jwt验证过程

        可将绑定的资源中src(ElementUI之Jwt)目录下的JwtUtils.javaJwtDemo.java导入到项目中的util包下:

1、生成Jwt令牌

//定义私有声明
Map<String, Object> claims = new HashMap<String, Object>();
claims.put("username", "zss");
claims.put("age", 18);
//根据私有声明和JWT的token有效时间生成JWT
String jwt = JwtUtils.createJwt(claims, JwtUtils.JWT_WEB_TTL);//获取JWT中的声明信息,包括:私有声明和标准声明
Claims parseJwt = JwtUtils.parseJwt(jwt);
for (Map.Entry<String, Object> entry : parseJwt.entrySet()) {System.out.println(entry.getKey() + "=" + entry.getValue());
}
//获取token令牌的签发时间
Date d1 = parseJwt.getIssuedAt();
//获取token令牌的过期时间
Date d2 = parseJwt.getExpiration();
System.out.println("令牌签发时间:" + sdf.format(d1));
System.out.println("令牌过期时间:" + sdf.format(d2));

2、解析旧的Jwt

 解析旧的JWT。如果超过JWT本身定义的过期时间,则直接抛出ExpiredJwtException

//旧的JWT令牌
String oldJwt = "eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1NjM2NzY0NDQsImlhdCI6MTU2MzY3NDY0NCwiYWdlIjoxOCwianRpIjoiMzE5MmYxOTg4NzFkNGVkZWIyMzU0MmY3NWVhMWI5NDciLCJ1c2VybmFtZSI6InpzcyJ92.4VnkdvGNNe8U1EiKaLz7h6bOJkVGSGtfqojcP_y-0Cc";
Claims parseJwt = JwtUtils.parseJwt(oldJwt);
for (Map.Entry<String, Object> entry : parseJwt.entrySet()) {System.out.println(entry.getKey() + "=" + entry.getValue());
}
Date d1 = parseJwt.getIssuedAt();
Date d2 = parseJwt.getExpiration();
System.out.println("令牌签发时间:" + sdf.format(d1));
System.out.println("令牌过期时间:" + sdf.format(d2));

 3、复制Jwt

模拟Session功能(Tomcat默认session过期时间:30分钟)。当有访问的情况下,自动延长jwt中的token令牌过期时间,在原有时间上+30秒;

String oldJwt = "eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1NjM2NzUzMDAsImlhdCI6MTU2MzY3MzUwMCwiYWdlIjoxOCwianRpIjoiYjY5MmE5ZjZkMGZhNDMyN2I1YWY2NTI5OGMzMjQ5MTYiLCJ1c2VybmFtZSI6InpzcyJ9.asHGMPFKURMLnooK29abAuKEdLOHBycAuTovNuGQio0";
String jwt = JwtUtils.copyJwt(oldJwt, JwtUtils.JWT_WEB_TTL);
Claims parseJwt = JwtUtils.parseJwt(jwt);
for (Map.Entry<String, Object> entry : parseJwt.entrySet()) {System.out.println(entry.getKey() + "=" + entry.getValue());
}
Date d1 = parseJwt.getIssuedAt();
Date d2 = parseJwt.getExpiration();
System.out.println("令牌签发时间:" + sdf.format(d1));
System.out.println("令牌过期时间:" + sdf.format(d2));

 4、Jwt有效时间测试

生成新的Jwt令牌,设置令牌有效时间3秒钟,在3秒钟后再次解析Jwt令牌提示令牌已过期。

Map<String, Object> claims = new HashMap<String, Object>();
claims.put("username", "zss");
String jwt = JwtUtils.createJwt(claims, 3 * 1000L);
System.out.println(jwt);
Claims parseJwt = JwtUtils.parseJwt(jwt);
Date d1 = parseJwt.getIssuedAt();
Date d2 = parseJwt.getExpiration();
System.out.println("令牌签发时间:" + sdf.format(d1));
System.out.println("令牌过期时间:" + sdf.format(d2));

 三、Jwt令牌刷新思路

        使用ssm+vue+elementui实现jwt验证。

1、配置JwtFilter过滤器

导入JwtFilter.java到utils包下,并注意配置顺序问题:CorsFilter > JwtFilter > SpringMVC核心控制器

<!-- JwtFilter -->
<filter><filter-name>jwtFilter</filter-name><filter-class>com.wsl.ssm.jwt.JwtFilter</filter-class>
</filter>
<filter-mapping><filter-name>jwtFilter</filter-name><url-pattern>/*</url-pattern>
</filter-mapping>

2、登录生成Jwt令牌

在登录成功后,使用JwtUtil工具类生成JWT,并将Jwt令牌添加到响应头(response)中带到前端页面。在这里可以将用户对应用户基本信息和用户角色信息保存到私有claim中。

if(userVo.getUsername().equals("admin")&&userVo.getPassword().equals("123")){//私有要求claimMap<String,Object> json=new HashMap<String,Object>();json.put("username", userVo.getUsername());//生成JWT,并设置到response响应头中String jwt=JwtUtils.createJwt(json, JwtUtils.JWT_WEB_TTL);response.setHeader(JwtUtils.JWT_HEADER_KEY, jwt);return new JsonResponseBody<>("用户登陆成功!",true,0,null);
}else{return new JsonResponseBody<>("用户名或密码错误!",false,0,null);
}

3、配置CorsFilter过滤器

浏览器只能访问默认的响应头,例如:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma等如果想让浏览器能访问到其他的响应头的话,需要在服务器上设置。在CorsFilter跨域过滤器的doFilter方法中配置其他响应头的支持。

//允许客户端发一个新的请求头jwt
httpResponse.setHeader("Access-Control-Allow-Headers","Origin,X-Requested-With, Content-Type, Accept, jwt");
//允许客户端处理一个新的响应头jwt
httpResponse.setHeader("Access-Control-Expose-Headers", "jwt");

 4、Vuex存储Jwt令牌

使用vuex保存后端服务器提交过来的Jwt,分别在state、getters、mutation中定义信息。

  • state.js
    export default {jwt:null
    }
  • getters.js
    export default {getJwt:(state)=>{return state.jwt;}
    }

  •  mutation.js
    export default {setJwt:function (state, payload){state.jwt = payload.jwt;}
    }

5、修改main.js

解决axios从响应头获得jwt令牌并保存到vuex,通过修改main.js中的配置window.vm=new Vue({});获取Vue根实例对象。

window.vm = new Vue({el: '#app',router,store,components: { App },template: '<App/>'
})

6、配置axios请求响应头

在vue的http.js中配置axios的请求响应拦截器,用于存取Jwt,并将Jwt信息保存到Vuex中。

// 请求拦截器
axios.interceptors.request.use(function(config) {let jwt=window.vm.$store.getters.jwt;//console.log(jwt);if(jwt)config.headers['jwt']=jwt;return config;
}, function(error) {return Promise.reject(error);
});// 响应拦截器
axios.interceptors.response.use(function(response) {let jwt=response.headers['jwt'];if(jwt)window.vm.$store.commit('setJwt',{jwt:jwt});return response;
}, function(error) {return Promise.reject(error);
});

注:可通过使用vuex-along解决刷新state初始化问题。

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

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

相关文章

R语言机器学习遥感数据处理与模型空间预测技术及实际项目案例分析

随机森林作为一种集成学习方法&#xff0c;在处理复杂数据分析任务中特别是遥感数据分析中表现出色。通过构建大量的决策树并引入随机性&#xff0c;随机森林在降低模型方差和过拟合风险方面具有显著优势。在训练过程中&#xff0c;使用Bootstrap抽样生成不同的训练集&#xff…

【案例75】全表扫描导致系统崩溃

问题现象 顾问反馈系统审批单据时&#xff0c;系统出现整体卡顿。操作审批单据本身比较长&#xff0c;在数据库中出现了死锁&#xff0c;死锁处理后&#xff0c;一审批单据就又会整体卡顿。 问题分析 开始怀疑有事务锁未释放导致的&#xff0c;先排查数据库当时的状态。发现…

AI写PPT工具:四款人工智能软件全面解析!!

嘿&#xff0c;小伙伴们&#xff01;今天咱们来聊聊那些能帮我们搞定PPT的神器——四款人工智能软件。有了它们&#xff0c;咱们再也不用为做PPT而头疼啦&#xff01; 第一款&#xff1a;笔灵AIPPT 直通车&#xff08;粘贴复制到网站打开&#xff09;&#xff1a;ibiling.c…

C++第八讲:STL--stack和queue的使用及模拟实现

C第八讲&#xff1a;STL--stack和queue的使用及模拟实现 1.stack的使用2.queue的使用3.栈和队列OJ题3.1题目1&#xff1a;最小栈3.2题目2&#xff1a;栈的压入、弹出序列3.3题目3&#xff1a;逆波兰表达式求值3.4题目4&#xff1a;用栈实现队列 4.栈的模拟实现5.队列的模拟实现…

103、QT搭建Excel表环境-使用Qtxlsx库

环境搭建 文件下载 下载QtXlsx源码&#xff1a;https://github.com/dbzhang800/QtXlsxWriter 下载的内容里面的目录结构如下&#xff1a; 搭建perl环境 官网链接: https://strawberryperl.com/ 下载后并安装 检验是否有perl环境的方法&#xff1a; perl --version安装前检…

Go语言基础教程:闭包

在这篇教程中&#xff0c;我们将通过一段简单的 Go 语言代码来理解闭包的概念。闭包是编程中非常强大且常用的工具&#xff0c;尤其适合实现像计数器这样的逻辑。我们将逐行讲解代码&#xff0c;并理解如何在 Go 中利用闭包来保存函数状态。 package mainimport "fmt&quo…

使用QT绘图控件QCustomPlot绘制波形图

使用QT绘图控件QCustomPlot绘制波形图 下载QCustomPlot 下载QCustomPlot,链接路径 解压之后就能看到源代码了 在Qt中添加QCustomPlot的帮助文档 在Qt Creator的菜单:工具–>选项–>帮助–>文档–>添加qcustomplot\documentation\qcustomplot.qch文件。

提升产品竞争力之--IPD产品成本篇

在汉捷的咨询过程中&#xff0c;很多企业老总交流时都会提起这个抱怨&#xff1a;“现在产品竞争太激烈了&#xff0c;客户买产品首先看价格&#xff0c;你价格高一点就买别家的啦……” 汉捷咨询在前文谈到“通过定义产品包需求&#xff0c;来提升产品竞争力。差异化开发&…

【OpenAI】第二节(Token)关于ChatGPT的Token你了解多少?最全Token讲解过程!

在当今的人工智能领域&#xff0c;GPT&#xff08;Generative Pre-trained Transformer&#xff09;无疑是最受关注的技术之一。无论是在文本生成、对话系统&#xff0c;还是在内容创作中&#xff0c;GPT都展现出了强大的能力。然而&#xff0c;很多人对GPT的工作原理仍然存在疑…

MobileViT模型实现图像分类

项目源码获取方式见文章末尾&#xff01; 回复暗号&#xff1a;13&#xff0c;免费获取600多个深度学习项目资料&#xff0c;快来加入社群一起学习吧。 **《------往期经典推荐------》**项目名称 1.【Bi-LSTM-CRF实现中文命名实体识别工具(TensorFlow)】 2.【卫星图像道路检测…

跨界创新|使用自定义YOLOv11和Ollama(Llama 3)增强OCR文本识别

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…

DevOps实践:在GitLab CI/CD中集成静态分析Helix QAC的工作原理与优势

基于云的GitLab CI/CD平台使开发团队能够简化其CI/CD流程&#xff0c;并加速软件开发生命周期&#xff08;SDLC&#xff09;。 将严格的、基于合规性的静态分析&#xff08;如Helix QAC所提供&#xff09;作为新阶段添加到现有的GitLab CI/CD流程中&#xff0c;将进一步增强SD…

如何使用 NumPy 和 Matplotlib 进行数据可视化

如何使用 NumPy 和 Matplotlib 进行数据可视化 在数据科学领域&#xff0c;NumPy 和 Matplotlib 是 Python 中最常用的两个库。NumPy 用于科学计算和数据处理&#xff0c;而 Matplotlib 提供了丰富的图表工具来展示数据。本文将介绍如何将这两个库结合使用&#xff0c;轻松进行…

现货黄金怎么交易能快速入门?

现货黄金交易的核心在于以小博大&#xff0c;即用较小的亏损去搏击较大的利润&#xff0c;成功不仅要靠资金上的管理&#xff0c;更需要心态和策略的支持。现货黄金交易的过程也是人性修炼的过程&#xff0c;新手投资者不仅要学会交易技巧&#xff0c;更需要学会控制情绪&#…

sql server 行转列及列转行

图1 图2 1.行转列 &#xff08;图1->图2&#xff09; 1.方法一 (数据库通用&#xff09;&#xff0c;使用max 加case when 函数 -- 行转列 图1->图2 SELECT name,MAX(CASE WHEN subject语文 THEN score ELSE 0 END) AS "语文",MAX(CASE WHEN subject数学 …

雷池社区版有多个防护站点监听在同一个端口上,匹配顺序是怎么样的

如果域名处填写的分别为 IP 与域名&#xff0c;那么当使用进行 IP 请求时&#xff0c;则将会命中第一个配置的站点 以上图为例&#xff0c;如果用户使用 IP 访问&#xff0c;命中 example.com。 如果域名处填写的分别为域名与泛域名&#xff0c;除非准确命中域名&#xff0c;否…

将后端返回的网络url转成blob对象,实现pdf预览

调用e签宝返回的数据是网络链接就很让人头疼&#xff0c;最后想到可以转换成blob对象&#xff0c;便在百度上找到方法&#xff0c;记录一下。 祝大家节日快乐&#xff01;&#xff01; 代码在最后&#xff01;&#xff01;&#xff01;&#xff01; 代码在最后&#xff01;&a…

Yandex搜索广告开户与投放全攻略!

Yandex 是俄罗斯最大的搜索引擎与数字广告平台&#xff0c;在俄罗斯市场具有广泛的影响力和庞大的用户基础。以下是 Yandex 搜索广告开户与投放的全攻略&#xff0c;包括云衔科技支持的相关服务。 一、Yandex 搜索广告的优势 1、广泛的市场覆盖&#xff1a;Yandex 在俄罗斯的…

Git合并多个分支中的提交内容

IDEA中使用 IEAD编辑器中使用Git IEAD编辑器中使用Git 案例一&#xff1a; 把test分支的其中提交的内容合并到main分支上。 你现在通过IDEA开发的分支是test分支&#xff0c;当你在test分支把内容都写完了并且提交内容保存到了本地的git暂存区中的时候&#xff0c;如果此时你的…

接口测试(九)jmeter——关联(JSON提取器)

一、JSON提取器介绍 要检查的响应字段&#xff1a;样本数据源引用名称&#xff1a;可自定义设置引用方法&#xff1a;${引用变量名}匹配数字 匹配数字含义-1表示全部0随机1第一个2第二个…以此类推 缺省值&#xff1a;匹配失败时的默认值ERROR&#xff0c;可以不写 二、js…