JWT介绍和使用

server/2024/9/22 17:39:31/

JWT_0">JWT介绍和使用

JWT_1">JWT介绍

JWT(JSON Web Token)是一个开放的标准(RFC 7519),JWT定义了一种简介的、自包含的协议格式。可以用于在通信的双方传递json对象,传递的信息可以被信任,因为信息是被数字签名的。JWT可以使用HMAC算法或者使用RSA/ECDSA算法的公钥/私钥对签名。

JWT_4">JWT格式

JWT包含三部分内容,Header、Plyload和Signature。

  • Header

    • 包括令牌的类型以及使用的哈希算法;使用base64url编码后就是JWT的第一部分内容
  • Payload

    • Payload的内容是一个json对象,它是存放有效信息的地方,可以存放jwt提供的现成字段,比如:iss(签发者),exp(过期时间戳信) ,sub(面向的用户)等;同时也可以自定义字段存放数据,但是不建议存放敏感数据,因为此部分可以解码还原原始内容;使用base64url编码后就是JWT的第二部分内容
  • Signature

    • Signature是签名,用于防止jwt内容被篡改,这个部分使用base64url将前两部分进行编码,编码后使用“.” 连接组成字符串,最后使用header中声明的签名算法进行签名。

假设现在一个JWT的Header和Payload部分内容如下
Header:

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

payload

{"sub": "1234567890","name": "John Doe","admin": true,"iat": 1516239022
}

那么Signature的的内容如下所示,“yguyhdqwodqwddqw1”是秘钥

HMACSHA384(base64UrlEncode(header) + "." +base64UrlEncode(payload),yguyhdqwodqwddqw1
)

最后生成的JWT如下:

eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.f7IalcwE38sVPor1FBUwAwso6exiwF80y0nM6bLkAvooNFGjCoJXRL0DMpaQB42C

payload和claims介绍

payload和claims的概念在JJWT开源库中使用了,所以这里简单介绍一下。

前面已经讲过了payload是一个JSON对象,包含了实际传输的数据。而Payload的主要目的是携带与特定用户或请求相关的信息,这些信息就被称为“claims”。

Claims(声明)是Payload中包含的具体键值对数据项,它们用来表述特定的声明或声明集,这些声明描述了与JWT相关的事实。根据其用途和规范要求,claims可以分为以下几类:

  • Reserved Claims(保留声明): 这些是JWT标准中预定义的、具有特殊含义的claims。虽然它们是可选的,但如果使用,应遵循标准规定的名称和格式。常见的保留claims包括:
    • iss(issuer):签发者。
    • sub(subject):主题,标识JWT所代表的个体。
    • aud(audience):接收方,标识预期的JWT接收者。
    • exp(expiration time):过期时间,定义了JWT的有效期截止时间。
    • nbf(not before):生效时间,在此时间之前JWT不应被接受处理。
    • iat(issued at):签发时间,表明JWT的创建时间。
    • jti(JWT ID):唯一标识符,用于防止JWT重放攻击。
  • Public Claims(公共声明)
    • 这些claims没有在JWT标准中明确规定,但可以通过IANA JSON Web Token Registry进行注册,以确保其名称在全球范围内是唯一的,避免不同系统间的冲突。公共claims通常用于满足特定的应用程序或行业需求。
  • Private Claims(私有声明)
    • 开发者可以自由定义的claims,用于承载应用程序所需的任何额外信息。私有claims无需注册,其名称由开发者自行决定,如示例中提到的user_id和user_name。这些声明对JWT的使用者具有特定意义,但对JWT标准本身来说是无特殊含义的。

JWT_69">JWT使用

jjwt是Java Json Web Tokens的缩写,它所示一个用于在Java中实现JWT的开源库。

jjwt依赖

        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version></dependency><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-api</artifactId><version>0.11.2</version></dependency><!-- javax.xml.bind.DatatypeConverter 类已被弃用并从 Java SE 9 中移除--><dependency><groupId>javax.xml.bind</groupId><artifactId>jaxb-api</artifactId><version>2.3.1</version></dependency>

这是自己写的JJWT工具类

java">public class JJWTUtils {private static final Logger logger = LoggerFactory.getLogger(JJWTUtils.class);private static final String SECRET = "mpd';dqw823djq3d902";/*** 生成token*/public static String getToken(Map<String, Object> map) {//设置内容JwtBuilder jwtBuilder = Jwts.builder().setClaims(map);Calendar instance = Calendar.getInstance();instance.add(Calendar.SECOND, 100);//设置过期时间, 100s后过期jwtBuilder.setExpiration(instance.getTime());String token = jwtBuilder.signWith(SignatureAlgorithm.HS256, SECRET.getBytes()).compact();return token;}/*** 校验token* @param token  jwt字符串* @return*/public static boolean verifyToken(String token) {String[] tokenSplit = token.split(".");String header = tokenSplit[0];String payload = tokenSplit[1];String signature = tokenSplit[2];String headerJson = new String(Base64.getDecoder().decode(header));String payloadJson = new String(Base64.getDecoder().decode(payload));byte[] keyBytes = SECRET.getBytes(StandardCharsets.UTF_8);Key signingKey = Keys.hmacShaKeyFor(keyBytes);// 验证JWT签名,如果JWT签名无效,这里会抛出SignatureException异常boolean result = true;try {Jwts.parser().setSigningKey(signingKey).parse(token);} catch (Exception e) {result = false;}return result;}/*** 获取token中的携带的信息*/public static Map<String, Object> getPayload(String token) {//claims是一个Map,存放了通过JwtBuilder设置进去的内容Claims claims = Jwts.parser().setSigningKey(SECRET.getBytes()).parseClaimsJws(token).getBody();return claims;}public static void main(String[] args) {HashMap<String, Object> payload = new HashMap<>();payload.put("name", "张三");payload.put("id", "1");String token = JJWTUtils.getToken(payload);logger.info("token: " + token);Map<String, Object> payload1 = JJWTUtils.getPayload(token);logger.info("payload1: " + payload1);}}

jjwt使用的坑

问题1
java.lang.ClassNotFoundException: javax.xml.bind.DatatypeConverter at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641) at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188) at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520) … 6 more

解决方法
这个错是由于在Java8以后,javax.xml.bind.DatatypeConverter 类已被弃用并从 Java SE 9 中移除而导致的,所以加入缺少的依赖即可

        <dependency><groupId>javax.xml.bind</groupId><artifactId>jaxb-api</artifactId><version>2.3.1</version></dependency>

问题2
ava.lang.IllegalStateException: Both ‘payload’ and ‘claims’ cannot both be specified. Choose either one. at io.jsonwebtoken.impl.DefaultJwtBuilder.compact(DefaultJwtBuilder.java:262) at com.example.sso.utils.JJWTUtils.getToken(JJWTUtils.java:38) at com.example.sso.utils.JJWTUtils.main(JJWTUtils.java:58)

解决方法

不能同时设置payload和claims。

参考

  1. Introduction to JSON Web Tokens

http://www.ppmy.cn/server/21191.html

相关文章

Pandas 2.2 中文官方教程和指南(十七)

原文&#xff1a;pandas.pydata.org/docs/ 重复标签 原文&#xff1a;pandas.pydata.org/docs/user_guide/duplicates.html Index对象不需要是唯一的&#xff1b;你可以有重复的行或列标签。这一点可能一开始会有点困惑。如果你熟悉 SQL&#xff0c;你会知道行标签类似于表上的…

【golang学习之旅】Go 的循环结构

系列文章 【golang学习之旅】报错&#xff1a;a declared but not used 【golang学习之旅】Go 的基本数据类型 目录 系列文章for循环基本的for循环for 变 while死循环 for-range for循环 Go 只有一种循环结构&#xff1a;for 循环 基本的for循环 和C以及Java语言一样&#xf…

【信号处理】基于CNN自编码器的心电信号异常检测识别(tensorflow)

关于 本项目主要实现卷积自编码器对于异常心电ECG信号的检测和识别&#xff0c;属于无监督学习中的生理信号检测的典型方法之一。 工具 方法实现 读取心电信号 normal_df pd.read_csv("/heartbeat/ptbdb_normal.csv").iloc[:, :-1] anomaly_df pd.read_csv(&quo…

Linux网络编程---多进/线程并发服务器

一、多进程并发服务器 实现一个服务器可以连接多个客户端&#xff0c;每当accept函数等待到客户端进行连接时 就创建一个子进程 思路分析&#xff1a; 核心思路&#xff1a;让accept循环阻塞等待客户端&#xff0c;每当有客户端连接时就fork子进程&#xff0c;让子进程去和客户…

Opencv_3_图像对象的创建与赋值

ColorInvert.h 如下&#xff1a; #include <opencv.hpp> using namespace std; #include <opencv.hpp> using namespace cv; using namespace std; class ColorInvert{ public : void mat_creation(); }; ColorInvert.cpp 文件如下&#xff1a; #include &q…

算法训练营第48天|LeetCode 198.打家劫舍 213.打家劫舍Ⅱ 337.打家劫舍Ⅲ

LeetCode 198.打家劫舍 题目链接&#xff1a; LeetCode 198.打家劫舍 代码&#xff1a; class Solution { public:int rob(vector<int>& nums) {int size nums.size();if (nums.size() 0) return 0;if(size 1) return nums[0];vector<int>dp(size,0);dp…

uni-app如何监测获取页面视图出现

在 uni-app 中&#xff0c;监测页面视图的出现或渲染完成&#xff0c;可以使用生命周期函数和一些自定义方法。这里有一些常见的方法&#xff1a; 使用生命周期函数&#xff1a; uni-app 提供了与页面生命周期相关的函数&#xff0c;如 onLoad、onShow、onReady 等。 onLoad…

Docker从无到有

主要为windows下docker的安装与使用~ 初始Docker Docker理解 对于docker的加简介&#xff0c;我们可以官网获取它的概念&#xff0c;接下来就从什么是docker、为什么要使用docker以及它的作用来进行一个快速入门 前提&#xff1a;项目在发布时&#xff0c;不仅需要其jar包同…