JWT 的使用

news2024/11/25 13:23:47

一、简介

JWT将用户的一些信息存储在客户端,访问后台时会带着JWT,服务器要对这个JWT进行检验。
由于signKey是存放在服务器端的,所以比较安全只要JWT被篡改就会立刻发现。

JWT认证的优势
1.简洁:JWT Token数据量小,传输速度也很快。
2.因为JWT Token是以JSON加密形式保存在客户端的,所以JWT是跨语言的,原则上任何web形式都支持。
3.不需要在服务端保存会话信息,也就是说不依赖于cookie和session,所以没有了传统session认证的弊端,特别适用于分布式微服务。
4.单点登录友好:使用Session进行身份认证的话,由于cookie无法跨域,难以实现单点登录。但是,使用token进行认证的话, token可以被保存在客户端的任意位置的内存中,不一定是cookie,所以不依赖cookie,不会存在这些问题。
5.适合移动端应用:使用Session进行身份认证的话,需要保存一份信息在服务器端,而且这种方式会依赖到Cookie(需要 Cookie 保存 SessionId),所以不适合移动端。

JWT的缺点
1.安全性没法保证,所以 jwt 里不能存储敏感数据。jwt 的 载荷(payload) 没加密,只是用 Base64 编码。
2.无法中途废弃。因为一旦签发了一个 jwt,在到期之前始终都是有效的,如果用户信息发生更新了,只能等旧的 jwt 过期后重新签发新的 jwt。
3.续签问题。当签发的 jwt 保存在客户端,客户端一直在操作页面,按道理应该一直为客户端续长有效时间,要引入 Redis 解决。

1、session认证、 token认证

1.session认证

服务器保存一份用户信息在session中,认证成功后返回 cookie 值传递给浏览器,下次请求时就可以带上 cookie 值,服务器可识别是哪个用户发送的请求,是否已认证,是否登录过期等等。

2.token认证

是一串随机的字符(比如UUID),value 一般是用户ID,并且设置一个过期时间。 请求时请求头里封装token,后端接收到token 则根据 token 查下 redis,如果 token 不存在则跳到登录界面让用户重新登录,登录成功后返回一个 token 值给客户端。

2、JWT的数据结构

标头(Header)、有效载荷(Payload)、签名(Signature)。
在传输的时候,会将JWT的3部分分别进行Base64编码后用.进行连接形成最终传输的字符串。
JWTString = Base64(Header).Base64(Payload).HMACSHA256(base64UrlEncode(header)+"."+base64UrlEncode(payload),secret)

1.标头(Header)

通常由两部分组成: Token的类型(即JWT)和所使用的签名算法(如 HMAC SHA256或 RSA),如:{ “alg”: “HS256”, “typ”: “JWT”}
将由base64进行加密(该加密是可以对称解密的),用于构成 JWT 的第一部分,如: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

2.有效载荷(Payload)

系统业务需要的数据,主要包含几个部分:
iss(签发者),exp(过期时间戳), sub(面向的用户), aud(接收方), iat(签发时间),
大致样式:{ “sub”: “1234567890”, “name”: “John Doe”, “admin”: true},
这部也会通过base64进行加密,最终形成JWT的第二部分,如:eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ

3.签名(Signature)

把:标头(header)、编码的有效载荷(payload)、秘钥(secret)、标头中指定的算法,并对其进行签名。
公式为:编码后的header、编码后的payload、secret进行加密HMACSHA256( base64UrlEncode(header) + “.” + base64UrlEncode(payload), secret)。
最终生成JWT的第三部分SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

注意:secret是保存在服务器端的,jwt的签发生成也是在服务器端的,secret就是用来进行jwt的签发和验证,是服务端的私钥,在任何场景都不应该流露出去。

3、JWT的种类

nonsecure JWT: 未经过签名,不安全的JWT
JWS: 经过签名的JWT
JWE: payload部分经过加密的JWT

4、JWT的签名算法

创建签名,保证jwt不被随意篡改,通常用的JWT一般都是JWS
HMAC【哈希消息验证码(对称)】:HS256/HS384/HS512
RSASSA【RSA签名算法(非对称)】(RS256/RS384/RS512)
ECDSA【椭圆曲线数据签名算法(非对称)】(ES256/ES384/ES512)

加密的算法
对称加密:secretKey 指加密密钥,可生成签名与验签
非对称加密:secretKey 指私钥,只用来生成签名,不能用来验签(验签用的是公钥)
JWT的密钥或者密钥对,一般统一称为JSON Web Key,就是JWK。

二、使用

1、JWT的流程(生成、校验)

1.生成

1、设置加密方式,payload 和 signingkey。
2、设置加密方式为 header,并进行base编码。
3、设置claims信息为payload,并进行base64编码。
4、对header和payload用"."拼接成jwt,使用signingkey按照加密方式进行加密,生成sign。
5、对Jwt和sign用"."生成最终的jwt。

2.校验

1、设置jwt和signingkey。
2、按"."对jwt分成三部分,即:header、payload、sign。
3、取第一部分进行base64解码,获取加密方式。
4、取第二部分进行base64解码,获取业务参数,即payload。
5、使用加密方式和signingkey创建校验器,对header+payload进行加密,并与sign(即第三部分)进行对比。
6、取出payload的有效期进行校验,是否过期。
7、通过校验,返回claims信息。

2、java-jwt 版本使用

1.引入依赖

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

2.代码

public class JWTUtils {
	
	// 过期时间(分钟)
	private static final int EXPIRE_TIME = 30;

    // 签名密钥(对称加密)
    private static final String SECRET = "!DAR$";
	
	// 非对称
	private static final String RSA_PRIVATE_KEY = "jun_south";
	
	// 非对称
	private static final String RSA_PUBLIC_KEY = "south_jun";
	
    /**
	 * 获取Token(对称)
     */
    public static String getToken(Map<String,String> payload){
        // 指定token过期时间为1天
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.MINUTE, EXPIRE_TIME);
        JWTCreator.Builder builder = JWT.create();
        // 构建payload
        payload.forEach((k,v) -> builder.withClaim(k,v));
        // 指定过期时间和签名算法
        String token = builder.withExpiresAt(calendar.getTime()).sign(Algorithm.HMAC256(SECRET));
        return token;
    }


    /**
     * 解析 token (对称)
     */
    public static DecodedJWT decode(String token){
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(SECRET)).build();
        DecodedJWT decodedJWT = jwtVerifier.verify(token);
        return decodedJWT;
    }
	
	/**
	 * 获取Token(非对称)
	 * @param payload token携带的信息
	 * @return token字符串
	 */
	public static String getTokenRsa(Map<String,String> payload){
		// 指定token过期时间为7天
		Calendar calendar = Calendar.getInstance();
		calendar.add(Calendar.MINUTE, EXPIRE_TIME);
		JWTCreator.Builder builder = JWT.create();
		// 构建payload
		payload.forEach((k,v) -> builder.withClaim(k,v));
		// 利用hutool创建RSA
		RSA rsa = new RSA(RSA_PRIVATE_KEY, null);
		// 获取私钥
		RSAPrivateKey privateKey = (RSAPrivateKey) rsa.getPrivateKey();
		// 签名时传入私钥
		String token = builder.withExpiresAt(calendar.getTime()).sign(Algorithm.RSA256(null, privateKey));
		return token;
	}

	/**
	 * 解析token(非对称)
	 * @param token token字符串
	 * @return 解析后的token
	 */
	public static DecodedJWT decodeRsa(String token){
		// 利用hutool创建RSA
		RSA rsa = new RSA(null, RSA_PUBLIC_KEY);
		// 获取RSA公钥
		RSAPublicKey publicKey = (RSAPublicKey) rsa.getPublicKey();
		// 验签时传入公钥
		JWTVerifier jwtVerifier = JWT.require(Algorithm.RSA256(publicKey, null)).build();
		DecodedJWT decodedJWT = jwtVerifier.verify(token);
		return decodedJWT;
	}
}

3、jjwt-root 版本使用

1.引入依赖

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-api</artifactId>
    <version>0.11.5</version>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-impl</artifactId>
    <version>0.11.5</version>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-jackson</artifactId>
    <version>0.11.5</version>
    <scope>runtime</scope>
</dependency>

2.代码

public class JwtUtils {
	
    // token时效:30 分钟
    public static final long EXPIRE = 1000 * 60 * 30 ;
	
    // 签名哈希的密钥,对于不同的加密算法来说含义不同
    public static final String APP_SECRET = "ukc8BDbRigUDaY6pZFfWus2jZWLPHOsdadasdasfdssfeweee";
	
	private static final String RSA_PRIVATE_KEY = "jun-south";
	
	private static final String RSA_PUBLIC_KEY = "south-jun";
	
   /**
	 * 根据用户id和名称生成token(对称)
	 */
    public static String getJwtToken(String id, String nickname){
        String JwtToken = Jwts.builder()
                .setSubject("jun-user")
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRE))
                .claim("id", id)
                .claim("nickname", nickname)
                // 传入Key对象
                .signWith(Keys.hmacShaKeyFor(APP_SECRET.getBytes(StandardCharsets.UTF_8)), SignatureAlgorithm.HS256)
                .compact();
        return JwtToken;
    }

	/**
	 * 解析token(对称)
     */
    public static Jws<Claims> decode(String jwtToken) {
        // 传入Key对象
        Jws<Claims> claimsJws = Jwts.parserBuilder().setSigningKey(Keys.hmacShaKeyFor(APP_SECRET.getBytes(StandardCharsets.UTF_8))).build().parseClaimsJws(jwtToken);
        return claimsJws;
    }
	
   /**
	 * 根据用户id和名称生成token(非对称)
	 */
	public static String getJwtTokenRsa(String id, String nickname){
		// 利用hutool创建RSA
		RSA rsa = new RSA(RSA_PRIVATE_KEY, null);
		RSAPrivateKey privateKey = (RSAPrivateKey) rsa.getPrivateKey();
		String JwtToken = Jwts.builder()
			.setSubject("jun-user")
			.setIssuedAt(new Date())
			.setExpiration(new Date(System.currentTimeMillis() + EXPIRE))
			.claim("id", id)
			.claim("nickname", nickname)
			// 签名指定私钥
			.signWith(privateKey, SignatureAlgorithm.RS256)
			.compact();
		return JwtToken;
	}

	/**
	 * 解析token(非对称)
     */
	public static Jws<Claims> decodeRsa(String jwtToken) {
		RSA rsa = new RSA(null, RSA_PUBLIC_KEY);
		RSAPublicKey publicKey = (RSAPublicKey) rsa.getPublicKey();
		// 验签指定公钥
		Jws<Claims> claimsJws = Jwts.parserBuilder().setSigningKey(publicKey).build().parseClaimsJws(jwtToken);
		return claimsJws;
	}
}

4、过滤器里的代码

	String JWT = request.getHeader("Authorization");
	try {
		// 1.校验JWT字符串
		DecodedJWT decodedJWT = JWTUtils.decode(JWT);
		// 2.取出JWT字符串载荷中的随机token,从Redis中获取用户信息
		...
		return true;
	}catch (SignatureVerificationException e){
		System.out.println("无效签名");
		e.printStackTrace();
	}catch (TokenExpiredException e){
		System.out.println("token已经过期");
		e.printStackTrace();
	}catch (AlgorithmMismatchException e){
		System.out.println("算法不一致");
		e.printStackTrace();
	}catch (Exception e){
		System.out.println("token无效");
		e.printStackTrace();
	}

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

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

相关文章

WebRTC带宽评估 -- Transport-wide Congestion Control

简述&#xff1a;在RTP包中增加transport-wide-cc扩展头&#xff0c;放置传输层面的包序号。视频接收端记录RTP包的接收时间&#xff0c;并通过RTCP Feedback消息反馈到视频发送端&#xff0c;发送端结合缓存的RTP包发送时间&#xff0c;基于丢包和延迟估算当前带宽&#xff0c…

zabbix 企业级监控 (3)Zabbix-server监控mysql及httpd服务

目录 web界面设置 server.zabbix.com 服务器操作 编辑 chk_mysql.sh脚本 查看web效果 web界面设置 1. 2. 3. 4. 5. 6. 7. 8. server.zabbix.com 服务器操作 [rootserver ~]# cd /usr/local/zabbix/etc/ [rootserver etc]# vim zabbix_agentd.conf UnsafeUserParameters1 Us…

Java当中的栈

栈的理解 栈&#xff08;Stack&#xff09;是一种受限的线性数据结构&#xff0c;所谓受限是指栈只暴露栈顶和栈底的操作&#xff0c;其底层是由数组实现的。栈的特性是先进后出。 常用方法 注意上面的peek()方法和pop()方法的区别&#xff01; 实例 import java.util.Stack…

【计算机视觉 | 图像分割】arxiv 计算机视觉关于图像分割的学术速递(7 月 19 日论文合集)

文章目录 一、分割|语义相关(12篇)1.1 Disentangle then Parse:Night-time Semantic Segmentation with Illumination Disentanglement1.2 OnlineRefer: A Simple Online Baseline for Referring Video Object Segmentation1.3 MarS3D: A Plug-and-Play Motion-Aware Model for…

LeetCode74.Search-A-2d-Matrix<搜索二维矩阵>

题目&#xff1a; 思路&#xff1a; 矩阵&#xff0c;搜索数是否在矩阵内。那就查找他是否在每一行中。如果符合这一行的范围&#xff0c;那就一直找这一列是否存在&#xff0c;如果存在返回true&#xff1b;否则false&#xff1b; 代码是&#xff1a; //codeclass Solution …

Istio 安全管理 加密证书中心

1 tls认证 2 设置ACL 允许哪些客户端可以访问 哪些客户端不能访问 3 istio里面的认证 加密是可以分为三种类型 对称加密&#xff08;加密和解密用的是同一个密钥&#xff09;非对称加密哈希函数 对称加密 A要发送数据传送给B&#xff0c;那么A要使用一个密钥&#xff0c;里面…

MySQL-数据库读写分离(下)

♥️作者&#xff1a;小刘在C站 ♥️个人主页&#xff1a; 小刘主页 ♥️努力不一定有回报&#xff0c;但一定会有收获加油&#xff01;一起努力&#xff0c;共赴美好人生&#xff01; ♥️学习两年总结出的运维经验&#xff0c;以及思科模拟器全套网络实验教程。专栏&#xf…

Verilog 学习之路二——基础学习总结(摘取自菜鸟教程)

目录 1 Verilog 设计方法2. 基础语法2.1 格式2.2 数值表示数值种类表示方法 2.3 数据类型2.4 表达式 3. 编译指令4. 连续赋值5. 过程结构6 过程赋值7 时序控制8 语句块9 循环10 函数例子-数码管译码 1 Verilog 设计方法 Verilog 的设计多采用自上而下的设计方法&#xff08;to…

TypeScript + React 环境搭建

React 安装 vscode 或者 webstrom 代码编辑器TypeScript 开发环境搭建1.1、下载 node.js1.2、安装 node.js1.3、npm 安装 typeScript1.4、创建和编写 ts 文件1.5、编译1.6、运行 js文件 React 环境搭建2.1、homebrow2.2、安装 cnpm&#xff1a;2.3、安装yarn&#xff1a;2.4、安…

[oeasy]python0074[专业选修]字节序_byte_order_struct_pack_大端序_小端序

进制转化 回忆上次内容 上次 总结了 计算字符串值的函数 eval 四种进制的转化函数 binoctinthex 函数名前缀目标字符串所用进制bin0b二进制oct0o八进制hex0x十六进制eval无前缀十进制 数字41 和 字符串"41" 的不同 字符串"41" 两个字符字符存储依据是…

部署ELK+Kafka+Filebeat日志收集分析系统

部署ELKKafkaFilebeat日志收集分析系统 文章目录 部署ELKKafkaFilebeat日志收集分析系统一、ELK 简介1、ELK日志分析系统组成2、Elasticsearch&#xff08;es&#xff09;3、Logstash4、Kibana5、日志处理步骤 二、Elasticsearch介绍1、Elasticsearch核心概念2、开启分片副本的…

AcWing 244. 谜一样的牛—树状数组、二分

题目链接 AcWing 244. 谜一样的牛 题目描述 分析 这道题挺巧妙的&#xff0c;感觉树状数组方面的题就是比较难想&#xff0c;先分析一下样例&#xff0c;样例中每头牛前面比自己低的牛的数量分别为 0 1 2 1 0牛的高度是1~n的排列&#xff0c;如何分析出每头牛的高度呢&…

Linux学习之if判断的使用

if的基本用法 if后边可以直接跟着命令。 echo "good" > ifecho.txt把good输出到当前目录下ifecho.txt文件里边&#xff0c;cat ifecho.txt首先可以看一下这个文件里边的内容。 然后依次输入&#xff1a; if cat ifecho.txt thenecho "right" fi可以看…

Windows系统实现唤醒+合成+命令词智能语音交互

1、之前写过离线能力调用&#xff0c;今天来个终极版&#xff0c;实现智能交互或者结合大模型的智能交互示例&#xff0c;下面进入正题。上B站效果离线唤醒离线合成离线命令词实现智能交互_哔哩哔哩_bilibili 2、到讯飞开放平台下载唤醒合成命令词的离线组合包&#xff0c;找到…

关于正则表达式的简单介绍以及使用

一、介绍 正则表达式通常被用来检索匹配某种模式&#xff08;规律&#xff09;的文本 日常文本检索&#xff0c;如果单纯检索某个数字&#xff0c;字母&#xff0c;或者单词匹配出来的结果较多&#xff0c;而面对目标文件内容较大的时&#xff0c;我们也不可能肉眼对检索出来的…

Kotlin 新版本 1.9.0重要更新预览

释放 Kotlin 新版本 1.9.0 的强大功能 1. Kotlin K2编译器用于多平台 对K2编译器进行了进一步的改进&#xff0c;使其更加稳定。K2编译器针对JVM目标现已进入Beta版本&#xff0c;并且也可以在多平台项目中使用。 您可以通过将K2配置添加到项目的gradle.properties中&#x…

pytest-allure 生成测试报告

目录 前言&#xff1a; pytest 中 yield 和 return 的区别和相同点 共同点 区别 usefixtures 与传 fixture 区别 Pytest 常用的插件 一键安装多个模块 前言&#xff1a; 在软件测试中&#xff0c;生成清晰、易读的测试报告是非常重要的。pytest-allure是一个流行的测试…

centos逻辑分区磁盘扩展

最近碰到服务器磁盘空间不足&#xff0c;需要扩展逻辑分区的需求&#xff0c;特地做下小笔记&#xff0c;方便后续自己回忆。下图是磁盘的相关概念示意图&#xff1a; 1、查看磁盘空间 [rootlocalhost ~]# df -h #查看磁盘空间&#xff0c;根分区的大小是18G&#xff0c;已经用…

微服务——Eureka和Nacos

目录 提供者和消费者 ​编辑 Eureka注册中心——远程调用的问题 Eureka注册中心——原理分析 Eureka注册中心——搭建eureka服务 步骤: Eureka注册中心——服务注册 Eureka注册中心——服务发现 总结 Ribbon负载均衡——原理 流程: Ribbon负载均衡——策略 Ribbon负载均衡—…

ChatGPT:人工智能语言模型的革命性进步

&#x1f337;&#x1f341; 博主 libin9iOak带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33…