springboot2入门到实战 - JWT

JWT是什么?

JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object。

This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA or ECDSA.

  • 基于JSON格式用于网络传输的令牌。
  • 紧凑的Claims声明格式。
  • Claim有索赔、声称、要求或者权利要求的含义。

在JWT之前

在JWT技术大规模应用之前,使用cookie+session技术做交互验证、存储由来已久。尤其在单体结构中更加突出(即使现在好多单体架构的项目依然使用cookie+session的经典组合)。

cookie+session技术之所以产生是由于HTTP协议在创建之初为加快服务器的响应,采用“无记忆性“来提高服务器的响应。但是会产生一系列的问题。例如:服务器如何确定客户端已经连接,已经登录了系统多长时间,是否允许该用户继续访问,该用户是否任然活跃,该用户如何找到其私有信息等问题等。
为此cookie+session技术很好的补充了http协议中“无记忆性“的问题。解决方案如图。

  • 服务器产生存储session对象,每个session对象有唯一的ID,有存活时间,可以记录数据。
  • 发起请求后,服务器将session的id写入客户端(浏览器),客户端通过cookie记录session的id
  • 客户端每一次发起请求需要携带session的id。
  • 服务器根据session的id查询指定session是否存在,然后交互。

image-20231026152201240

cookie-session模型很好的补充了http协议的无记忆性问题,但是如果在分布式环境下,如果每个服务器产生一个session或同步已有的session很困难,如果网络,服务器等由于延迟保证数据一致性比较困难。
为此我们需要一种轻量级,在分布式情况下依然能使用的技术尤为重要,JWT技术由此产生。

jwt的结构

image-20230515144726146

xxx.yyy.pppp

Header 部分是一个 JSON 对象,描述 JWT 的元数据。

image-20230515153047351

加密算法
  • HSA256

    SHA(Secure Hash Algorithm,安全散列算法)是一个密码散列函数家族,由美国国家安全局(NSA)设计,并由美国国家标准与技术研究院(NIST)发布,是美国的政府标准。

    • 无论输入多长,都输出64个字符,共32字节(byte),256位(bit)
    • 输出只包含数字0`9`和字母`A`F,大小写不敏感
  • RSA256

    由美国麻 省理工 学院三 位学者 Riv est、Sh amir 及Adleman 研 究发 展出 一套 可实 际使用 的公 开金 钥密码系 统,那 就是RSA(Rivest-Shamir-Adleman)密码系统。

    RS256(带有SHA-256的 RSA 签名)是一种非对称算法,它使用公钥/私钥对:身份提供者拥有用于生成签名的私钥(秘密)密钥,而 JWT 的消费者获得公钥验证签名。由于与私钥相反,公钥不需要保持安全,因此大多数身份提供者都可以让消费者轻松获取和使用(通常通过元数据 URL)。

Base64

Base64是一种基于64个可打印字符来表示二进制数据的表示方法。Base64不是加密算法,只是一种编码方式,可以用Base64来简单的“加密”来保护某些数据,所以每 6 个比特为一个单元,对应某个可打印字符。

image-20230515195043903

“hello” 编码

h–01101000 e --01100101

01101000

image-20230515201422170

 String str="hello";byte[] encode = Base64.getEncoder().encode(str.getBytes());String s = new String(encode);System.out.println("base64编码: "+s);byte[] decode = Base64.getDecoder().decode(s);String x = new String(decode);System.out.println("解析:" + x);

Payload

Payload 部分也是一个 JSON 对象,用来存放实际需要传递的数据。JWT 规定了7个官方字段,供选用。

Payload 也使用BASE64编码

Registered claims

这些是一组预先定义的声明,它们不是强制性的,但推荐使用,以提供一组有用的,可互操作的声明。 其中一些是:iss(发行者),exp(到期时间),sub(主题),aud(受众)等

序号名称解释
1iss (issuer)签发人
2exp (expiration time)过期时间
3sub (subject)主题
4aud (audience)受众(接收jwt的一方)
5nbf (Not Before)生效时间
6iat (Issued At)签发时间
7jti (JWT ID)jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击
Public claims

这些可以由使用JWT的人员随意定义。

Private claims

这些是为了同意使用它们但是既没有登记,也没有公开声明的各方之间共享信息,而创建的定制声明。

Payload案例
{"sub": "456781234","name": "Mr.zhang","admin": true
}

Signature

The signature is used to verify the message wasn’t changed along the way, and, in the case of tokens signed with a private key, it can also verify that the sender of the JWT is who it says it is.

Signature 部分是对前两部分的签名,防止数据篡改。

https://jwt.io/

Signature部分由编码后的Header、Payload和自定义的秘钥使用Header中指定的算法(HSA256)进行加密签名;

image-20230516085001222

image-20230516142821824

JWT构成

image-20230516085933230

jwt使用

maven中引入token依赖

<dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>4.3.0</version>
</dependency>

创建token字符串

//数据
User user = new User(1, "tom", "123", "tomcat");
Map<String, String> map = new HashMap<>();
map.put("username", user.getUsername());
map.put("name", user.getName());String token = JWT.create().withAudience(user.getUsername()).withExpiresAt(new Date(System.currentTimeMillis()+1000*30)) //设置过期时间为30ms.withClaim("data", map).sign(Algorithm.HMAC256(user.getPassword()));

输出token结果:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJ0b20iLCJkYXRhIjp7ImFtZSI6InRvbWNhdCIsInVzZXJuYW1lIjoidG9tIn0sImV4cCI6MTY4NDIyNTk5NX0.oLSSNY9JeBRrKilOroUZ_xT5AS7AODotUxBXeOZ_D40

解析token

DecodedJWT decode = JWT.decode(token);

获取token的内容

System.out.println("Header: " + decode.getHeader());
System.out.println("Payload: " + decode.getPayload());
System.out.println("Audience: " + decode.getAudience());
System.out.println("Signature: " + decode.getSignature());

验证token

JWTVerifier build = JWT.require(Algorithm.HMAC256(user.getPassword())).build();

获取信息

System.out.println(build.verify(token).getClaim("data"));

{“name”:“tomcat”,“username”:“tom”}

token出现的问题

私钥salt被人篡改

  String salt ="guess";String token = JWT.create().withClaim("name", "jack").withClaim("password","123").sign(Algorithm.HMAC256(salt));System.out.println(token);JWTVerifier build = JWT.require(Algorithm.HMAC256("abc")).build();build.verify(token);
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJwYXNzd29yZCI6IjEyMyIsIm5hbWUiOiJqYWNrIn0.ghK3Y79d1VU66eaay9YknYyW9MhWCrsth93UTx75-fk
Exception in thread "main" com.auth0.jwt.exceptions.SignatureVerificationException: The Token's Signature resulted invalid when verified using the Algorithm: HmacSHA256at com.auth0.jwt.algorithms.HMACAlgorithm.verify(HMACAlgorithm.java:57)at com.auth0.jwt.JWTVerifier.verify(JWTVerifier.java:463)at com.auth0.jwt.JWTVerifier.verify(JWTVerifier.java:445)at com.wnhz.bms.preview.jwt.JwtDemo.main(JwtDemo.java:19)

篡改token中的信息

     String salt ="guess";String token = JWT.create().withClaim("name", "jack").withClaim("password","123").sign(Algorithm.HMAC256(salt));System.out.println(token);token = token.replace("eyJwYXNzd29yZCI6IjEyMyIsIm5hbWUiOiJqYWNrIn0","eyJwYXNzd29yZCI7IjEyMyIsIm5hbWUiOiJqYWNrIn0");// token =  token.replace("K","W");//黑客// JWTVerifier build = JWT.require(Algorithm.HMAC256("abc")).build();JWTVerifier build = JWT.require(Algorithm.HMAC256(salt)).build();build.verify(token);
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJwYXNzd29yZCI6IjEyMyIsIm5hbWUiOiJqYWNrIn0.ghK3Y79d1VU66eaay9YknYyW9MhWCrsth93UTx75-fk
Exception in thread "main" com.auth0.jwt.exceptions.JWTDecodeException: The string '{"password";"123","name":"jack"}' doesn't have a valid JSON format.at com.auth0.jwt.impl.JWTParser.decodeException(JWTParser.java:90)at com.auth0.jwt.impl.JWTParser.parsePayload(JWTParser.java:47)at com.auth0.jwt.JWTDecoder.<init>(JWTDecoder.java:49)at com.auth0.jwt.JWTVerifier.verify(JWTVerifier.java:444)at com.wnhz.bms.preview.jwt.JwtDemo.main(JwtDemo.java:26)

token过期

        String salt ="guess";String token = JWT.create().withClaim("name", "jack").withClaim("password","123").withExpiresAt(new Date(System.currentTimeMillis()+10)).sign(Algorithm.HMAC256(salt));System.out.println(token);Thread.sleep(1000);JWTVerifier build = JWT.require(Algorithm.HMAC256(salt)).build();build.verify(token);
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJwYXNzd29yZCI6IjEyMyIsIm5hbWUiOiJqYWNrIiwiZXhwIjoxNjk4MzA4MTA1fQ.KGA8e6HhO3CSxanvhBaO9X2EpCQY20iZCn2fkSqdlNo
Exception in thread "main" com.auth0.jwt.exceptions.TokenExpiredException: The Token has expired on 2023-10-26T08:15:05Z.at com.auth0.jwt.JWTVerifier$BaseVerification.assertValidInstantClaim(JWTVerifier.java:346)at com.auth0.jwt.JWTVerifier$BaseVerification.lambda$addMandatoryClaimChecks$17(JWTVerifier.java:308)at com.auth0.jwt.JWTVerifier$BaseVerification$1.verify(JWTVerifier.java:405)at com.auth0.jwt.JWTVerifier.verifyClaims(JWTVerifier.java:482)at com.auth0.jwt.JWTVerifier.verify(JWTVerifier.java:464)at com.auth0.jwt.JWTVerifier.verify(JWTVerifier.java:445)at com.wnhz.bms.preview.jwt.JwtDemo.main(JwtDemo.java:23)

使用拦截器统一拦截方式

@Component
public class AuthInterceptor  implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String token = request.getHeader("bm_token");if (Objects.isNull(token) || "".equals(token.trim())) {throw new UserNoLoginException("用户名还没有登录异常");}return true;}
}
@Configuration
public class BmWebConfig implements WebMvcConfigurer {@Resourceprivate AuthInterceptor authInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(authInterceptor).excludePathPatterns("/api/login");}
}

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

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

相关文章

如何做代币分析:以 USDT 币为例

作者&#xff1a;lesleyfootprint.network 编译&#xff1a;cicifootprint.network 数据源&#xff1a;USDT Token Dashboard &#xff08;仅包括以太坊数据&#xff09; 在加密货币和数字资产领域&#xff0c;代币分析起着至关重要的作用。代币分析指的是深入研究与代币相关…

CSS:弹性盒子Flexible Box布局

CSS:Flexible Box弹性盒子布局 一、flex布局原理 ​ flex是flexible Box的缩写,意为 ”弹性布局“&#xff0c;用来为盒状模型提供最大的灵活性&#xff0c;任何一个容器都可以指定为flex布局。 当我们的父盒子设置为flex布局之后&#xff0c;子元素的 float 、clear 和 vert…

用友 NC 23处接口XML实体注入漏洞复现

0x01 产品简介 用友 NC 是用友网络科技股份有限公司开发的一款大型企业数字化平台。 0x02 漏洞概述 用友 NC 多处接口存在XML实体注入漏洞,未经身份验证攻击者可通过该漏洞读取系统重要文件(如数据库配置文件、系统配置文件)、数据库配置文件等等,导致网站处于极度不安全…

国产动漫|基于Springboot的国产动漫网站设计与实现(源码+数据库+文档)

国产动漫网站目录 目录 基于Springboot的国产动漫网站设计与实现 一、前言 二、系统功能设计 三、系统功能设计 1、用户信息管理 2、国漫先驱管理 3、国漫之最管理 4、公告信息管理 四、数据库设计 1、实体ER图 五、核心代码 六、论文参考 七、最新计算机毕设选题…

k8s.gcr.io/pause:3.2镜像丢失解决

文章目录 前言错误信息临时解决推荐解决onetwo 前言 使用Kubernetes&#xff08;k8s&#xff09;时遇到了镜像拉取的问题&#xff0c;导致Pod沙盒创建失败。错误显示在尝试从k8s.gcr.io拉取pause:3.2镜像时遇到了超时问题&#xff0c;这通常是因为网络问题或者镜像仓库服务器的…

C++——类的6个默认成员函数

目录 类中的6个默认成员函数 构造函数 构造函数的特点 初始化列表 隐式类型转换 析构函数 拷贝构造函数 赋值重载 运算符重载 赋值重载 取地址重载 类中的6个默认成员函数 类中的6个默认成员函数根据不同的作用可以分为&#xff1a; 初始化和使用后清理&#xff1a;…

基于springboot实现保险信息网站系统项目【项目源码+论文说明】

基于springboot实现保险信息网站系统演示 摘要 随着互联网的不断发展&#xff0c;现在人们获取最新资讯的主要途径来源于网上新闻&#xff0c;当下的网上信息宣传门户网站的发展十分的迅速。而保险产品&#xff0c;作为当下人们非常关注的一款能够给人们带来医疗、生活、养老或…

[spark] RDD 编程指南(翻译)

Overview 从高层次来看&#xff0c;每个 Spark 应用程序都包含一个driver program&#xff0c;该程序运行用户的main方法并在集群上执行各种并行操作。 Spark 提供的主要抽象是 resilient distributed dataset&#xff08;RDD)&#xff0c;它是跨集群节点分区的元素集合&…

蓝桥杯_中断系统

一 中断 中断&#xff0c;即cpu暂停执行当前程序&#xff0c;转而执行另外一段特殊程序&#xff0c;处理结束后。返回之前暂停程序继续执行。 中断向量&#xff0c;中断服务程序的入口地址&#xff0c;每个中断源都对应一个固定的入口地址。 中断服务函数&#xff0c;内核响应中…

Transformer之self-attention

注意力是一个有助于提高神经机器翻译应用程序性能的概念。在这篇文章中&#xff0c;我们将看看Transformer&#xff0c;一个使用注意力来提高这些模型训练速度的模型。Transformer在特定任务中优于谷歌神经机器翻译模型。最大的好处来自于Transformer如何使自己适合并行化。 在…

虚拟机上为AzureDevOps Server 创建用户

为DevOpsServer创建登录用户 背景虚拟机的本地用户和组去DevOps Server上添加本地用户 背景 我们有一台虚拟机&#xff0c;然后在上面安装了一台Azure DevOps Server&#xff0c;然后我们创建几个登录用户。 虚拟机的本地用户和组 首先我们登陆到虚拟机&#xff0c;然后我们…

JVM的深入理解

1、JVM&#xff08;Java虚拟机&#xff09;&#xff1a;我们java编译时候&#xff0c;下通过把avac把.java文件转换成.class文件&#xff08;字节码文件&#xff09;&#xff0c;之后我们通过jvm把字节码文件转换成对应的cpu能识别的机器指令&#xff08;翻译官角色&#xff09…