【JWT】入门 *JWT*,并封装一个实用的 *JWT* 工具类

在这里插入图片描述

个人简介:Java领域新星创作者;阿里云技术博主、星级博主、专家博主;正在Java学习的路上摸爬滚打,记录学习的过程~
个人主页:.29.的博客
学习社区:进去逛一逛~

在这里插入图片描述


1. 什么是JSON Web Token(JWT)?

JSON Web 令牌(JWT)

JSON Web 令牌 (JWT) 是一种开放标准 (RFC 7519),它定义了一种紧凑且独立的方式,用于将信息作为 JSON 对象在各方之间安全地传输 。此信息可以被验证和信任,因为它是经过数字签名的。JWT 可以使用密钥(使用 HMAC 算法)或使用 RSAECDSA 的公钥/私钥对进行签名。



2. JWT使用场景

JWT使用场景

  • 授权:这是使用 JWT 的最常见方案。用户登录后,每个后续请求都将包含 JWT,从而允许用户访问该令牌允许的路由、服务和资源。单点登录是当今广泛使用 JWT 的一项功能,因为它的开销很小,并且能够轻松地跨不同域使用。
  • 信息交换:JSON Web 令牌是在各方之间安全传输信息的好方法。由于 JWT 可以签名(例如,使用公钥/私钥对),因此您可以确定发件人是他们所说的人。此外,由于签名是使用标头和有效负载计算的,因此您还可以验证内容是否未被篡改。



3. JWT结构

JSON Web Token 结构

JWT由三部分组成,分别是页眉(Header)、有效载荷(Payload)、签名(Signature) ,他们之间由符号.进行分割。

  • Header
  • Payload
  • Signature

因此,我们可知,JWT通常是这样的:ddddd.hhhhh.jjjjj


⚪页眉 Header


  • Header通常由两部分组成:令牌类型typ、使用的签名算法alg;
{
  "alg": "HS256",
  "typ": "JWT"
}

然后,这条JSON数据会经过Base64Url编码,组成JWT的第一部分(Header)



⚪有效载荷 Payload


JWT的第二部分是Payload,其中包含的是 Claims(声明), Claims是关于用户实体和其他数据的陈述。

有三种类型的Claims:registered claims public claimsprivate claims

  • **已注册的声明(registered claims):**是一组预定义的声明,这些声明不是强制性的,但建议提供一组有用的、可互操作的声明。比如:iss(发行人)、exp(到期时间)、sub(主题)、aud(受众)等…

    注意,上述提到的声明,名称的长度都是简短的几个字符,因为 JWT 应该是紧凑的。

  • 公共声明(public claims):这些声明可以由使用 JWT 的人随意定义。但为了避免冲突,应在 IANA JSON Web Token注册表中定义它们,或者将其定义为包含抗冲突命名空间的 URI。

  • 私人声明(private claims):这些声明是为了让同意使用它们的各方之间共享信息而创建的自定义声明,既不是 已注册 声明,也不是 公共 声明。


例如

{
  "sub": "123456789",
  "name": ".29.",
  "admin": true
}

接下来,这条JSON数据会经过Base64Url编码,组成JWT的第二部分(Payload)

请注意,对于已签名的令牌,此信息虽然受到保护,但任何人都可以读取。不要将机密信息放在 JWT 的有效负载或标头元素中,除非它是加密的。



⚪签名 Signature


要创建签名部分,必须获取经过Base64Url编码后的标头、经过Base64Url编码后的有效负载、密钥、标头中指定的算法,并对其进行签名。

例如,如果要使用 HMAC SHA256 算法,将按以下方式创建签名:

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



一个完整的JWT长什么样?

  • 下述JWT对Header 和 Payload 进行了Base64Url编码,并使用密钥进行了签名,三个三个 Base64-URL 字符串,由点.进行分隔。
  • 它可以在 HTML 和 HTTP 环境中轻松传递,同时与基于 XML 的标准(如 SAML)相比更紧凑。

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkiLCJuYW1lIjoiLjI5LiIsImFkbWluIjp0cnVlfQ.1M3o41CutZL1fTjEftuxs6g5ug5M-j6GcP_K61nAIjM

在这里插入图片描述




4. JWT基本使用(SpringBoot项目中)

导入maven坐标

        <!-- jjwt -->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>
        <!-- jaxb-api -->
        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.0</version>
        </dependency>
        <!-- jaxb-impl -->
        <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb-impl</artifactId>
            <version>2.3.0</version>
        </dependency>
        <!-- jaxb-api -->
        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.0</version>
        </dependency>

测试基本使用

/**
 * @author .29.
 * @create 2024-03-15 23:37
 */
@SpringBootTest
public class jwtTest {
    //签名密钥
    String signature = "admin";

    /**
     * 加密生成JWT的测试方法
     */
    @Test
    public void jwt(){
        JwtBuilder builder = Jwts.builder(); //获取JWT生成器
        //使用JWT生成器创建一个JWT
        String jwtToken = builder
                //Header
                .setHeaderParam("typ", "JWT")//类型
                .setHeaderParam("alg", "HS256")//使用的算法
                //Payload
                .claim("name", ".29.")
                .claim("role", "admin")
                .setSubject("admin-test")
                .setExpiration(new Date(System.currentTimeMillis() + 1000*60*60*24))//失效日期:当前时间+24小时
                .setId(UUID.randomUUID().toString())
                //signature
                .signWith(SignatureAlgorithm.HS256, signature)//使用的算法+签名密钥
                //调用compact()方法将三部分拼接起来并用'.'分隔
                .compact();
        System.out.println("生成的JWT:" + jwtToken);
    }

    /**
     * 解密JWT获取信息的测试方法
     */
    @Test
    public void parse(){
        //jwt方法加密出来的密钥
        String jwtToken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiLjI5LiIsInJvbGUiOiJhZG1pbiIsInN1YiI6ImFkbWluLXRlc3QiLCJleHAiOjE3MTA2MDUyMjYsImp0aSI6IjFmNTkwNmNjLWQ4MWMtNGQ0MS1hYmJiLWY2M2NkZTg5OTM0ZSJ9.sgkpuvWTyzwDbwmUeKjQt2IuuL2zG0NKrQofdItbBAU";
        JwtParser parser = Jwts.parser();//获取JWT解密工具
        Jws<Claims> claimsJws = parser.setSigningKey(signature).parseClaimsJws(jwtToken); //根据签名密钥对JWT进行解密
        Claims claims = claimsJws.getBody();
        //获取解密出来的载荷内容
        System.out.println("用户名:" + claims.get("name") + "\n"
                        + "规则:" + claims.get("role") + "\n"
                        + "主题:" + claims.getSubject() + "\n"
                        + "ID:" + claims.getId() + "\n"
                        + "失效时间(有效期至):" + claims.getExpiration()
        );
    }
}

jwt()输出:👇

生成的JWT:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiLjI5LiIsInJvbGUiOiJhZG1pbiIsInN1YiI6ImFkbWluLXRlc3QiLCJleHAiOjE3MTA2MDUzNzUsImp0aSI6IjYxYzUyNmQ1LTJkMDQtNGE1YS1hZWRmLTQwMDE5ZTc1ZmFmOSJ9.hhacIWFVfLJkDpNLlIHokShtNI1M_CTHUqKSIIUrfIw

/

parse()输出:👇

用户名:.29.
规则:admin
主题:admin-test
ID:1f5906cc-d81c-4d41-abbb-f63cde89934e
失效时间(有效期至):Sun Mar 17 00:07:06 CST 2024




5. 封装一个实用的JWT工具类

工具类JwtUtil.java:

/**
 * @author .29.
 * @create 2024-03-16 0:29
 * @description 生成JwtToken, 获取JwtToken中加密的信息, 判断JwtToken是否合法
 *
 */
public class JwtUtil {
    //创建默认的密钥与加密算法,提供给空参构造器调用
    private static final String defaultBase64EncodingSecretKey = "eb^29*be";
    private static final SignatureAlgorithm defaultSignatureAlgorithm = SignatureAlgorithm.HS256;

    public JwtUtil(){
        this(defaultBase64EncodingSecretKey, defaultSignatureAlgorithm);
    }

    private final String base64EncodingSecretKey;
    private final SignatureAlgorithm signatureAlgorithm;

    public JwtUtil(String base64EncodingSecretKry, SignatureAlgorithm signatureAlgorithm){
        this.base64EncodingSecretKey = base64EncodingSecretKry;
        this.signatureAlgorithm = signatureAlgorithm;
    }

    public String encoding(String issuer, long ttlMillis, Map<String, Object> claims){
        // iss签发人,ttlMillis生存时间,claims是指还想要在jwt中存储的一些非隐私信息
        if(claims == null){
            claims = new HashMap<>();
        }
        long nowMillis = System.currentTimeMillis();
        JwtBuilder builder = Jwts.builder()
                .setId(UUID.randomUUID().toString())
                .setSubject(issuer)
                .setClaims(claims)
                .setIssuedAt(new Date(nowMillis))
                .signWith(signatureAlgorithm, base64EncodingSecretKey);
        if(ttlMillis > 0){
            long exp = nowMillis + ttlMillis;
            Date date = new Date(exp);
            builder.setExpiration(date);
        }
        return builder.compact();
    }

    public Claims decoding(String jwtToken){
        JwtParser parser = Jwts.parser();
        Jws<Claims> claimsJws = parser.setSigningKey(base64EncodingSecretKey).parseClaimsJws(jwtToken);
        return claimsJws.getBody();
    }

    // 判断jwtToken是否合法
    public boolean isVerify(String jwtToken) {
        // 这个是官方的校验规则,这里只写了一个”校验算法“,可以自己加
        Algorithm algorithm = null;
        switch (signatureAlgorithm) {
            case HS256:
                algorithm = Algorithm.HMAC256(Base64.decodeBase64(base64EncodingSecretKey));
                break;
            default:
                throw new RuntimeException("不支持该算法");
        }
        JWTVerifier verifier = JWT.require(algorithm).build();
        verifier.verify(jwtToken);
        // 校验不通过会抛出异常
        // 判断合法的标准:1. 头部和荷载部分没有篡改过。2. 没有过期
        return true;
    }



}





在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SQLiteC/C++接口详细介绍之sqlite3类(八)

返回目录&#xff1a;SQLite—免费开源数据库系列文章目录 上一篇&#xff1a;SQLiteC/C接口详细介绍之sqlite3类&#xff08;七&#xff09; 下一篇&#xff1a; SQLiteC/C接口详细介绍之sqlite3类&#xff08;八&#xff09;&#xff08;暂未发表&#xff09; 24.sqlite3_cr…

网络安全msf学习1

工具&#xff1a;netcat 用途 &#xff1a;端口连接、数据提交 工具nmap 用途&#xff1a;端口扫描、服务识别、操作系统指纹识别 工具 httprint 用途&#xff1a;通过远程http指纹判断http服务类型 工具&#xff1a; tamper ie 用途&#xff1a; http数据包修改、转发工…

SpringMVC基础之工作流程

文章目录 SpringMVC 的工作流程1. 总图2. DispatcherServlet3. 必需的配置4. 加载配置文件的两个时机5. 定义控制器6. 创建 JSP 视图 SpringMVC 的工作流程 1. 总图 如上图&#xff0c;Spring MVC 程序的完整执行流程如下&#xff1a; 用户通过浏览器发送请求&#xff0c;请求…

怎样提升小程序日活?签到抽奖可行吗?

一、 日活运营策略 小程序应该是即用即走的&#xff0c;每个小程序都在用户中有自己的独特定位&#xff0c;可能是生活日常必备&#xff08;美食、团购、商城&#xff09;&#xff0c;也可能是工作办公必备&#xff08;文档、打卡、工具&#xff09;。 如果你想要让自己的小程…

sqllab第十九关通关笔记

知识点&#xff1a; 错误注入 最大长度为32位&#xff1b;如果目标长度>32时&#xff0c;需要利用截取函数进行分段读取referer注入 insert语句update语句 通过admin admin进行登录发现页面打印除了referer字段的信息 这应该是一个referer注入 首先进行测试一下 构造payl…

实现elasticsearch和数据库的数据同步

1. 数据同步 elasticsearch中的酒店数据来自于mysql数据库&#xff0c;因此mysql数据发生改变时&#xff0c;elasticsearch也必须跟着改变&#xff0c;这个就是elasticsearch与mysql之间的数据同步。 1.1. 思路分析 常见的数据同步方案有三种&#xff1a; 同步调用 异步通知…

在macOS上安装Homebrew教程

1.打开终端&#xff1a; 打开Finder&#xff0c;转到应用程序 > 实用工具文件夹&#xff0c;然后双击终端.app。 或者&#xff0c;使用Spotlight搜索&#xff08;按下 Command(⌘) Spacebar&#xff09;并输入“终端”&#xff0c;然后回车以打开。 也可以像我一样把终端…

【SQL Server】实验五 视图

1 实验目的 掌握SQL视图语句的基本使用方法&#xff0c;如CREATE VIEW、DROP VIEW。掌握视图更新、WITH CHECK OPTION等高级功能的使用。 2 实验内容 2.1 掌握SQL视图语句的基本使用方法 创建视图&#xff08;省略视图列名&#xff09;。创建视图&#xff08;不能省略列名的…

(三)丶RabbitMQ的四种类型交换机

前言&#xff1a;四大交换机工作原理及实战应用 1.交换机的概念 交换机可以理解成具有路由表的路由程序&#xff0c;仅此而已。每个消息都有一个称为路由键&#xff08;routing key&#xff09;的属性&#xff0c;就是一个简单的字符串。最新版本的RabbitMQ有四种交换机类型&a…

专业无网设备如何远程运维?向日葵远程控制能源场景案例解析

清洁能源领域&#xff0c;拥有庞大的上下游产业链&#xff0c;涉及的相关工业设备门类多、技术覆盖全、行业应用广。在这一领域内&#xff0c;相关专业设备的供应商的核心竞争力除了本身产品的技术能力之外&#xff0c;服务也是重要的一环。 某企业作为致力于节能环保方向的气…

XML语言的学习记录1

学习笔记&#xff1a; xml&#xff08;可扩展标记语言&#xff09;语言没有预定义的标签&#xff0c;都是使用者自定义&#xff1b;xml是纯文本&#xff0c;是不作为的&#xff1b;语法 每个标签必须有关闭标签&#xff1b;对大小写敏感&#xff1b;最外层必须有根元素&#x…

使用FFmpeg源码配置程序configure查看所有支持的编码器/解码器/封装/解封装及网络协议

查看支持编码器: configure --list-encoders 查看支持编码器: configure --list-decoders 查看所有支持的封装: configure --list-muxers 查看所有支持的解封装: configure --list-demuxers 查看所有支持的网络通信协议: configure --list-protocols

微服务学习day02 -- nacos配置管理 -- Feign远程调用 -- Gateway服务网关

0.学习目标 1.Nacos配置管理 Nacos除了可以做注册中心&#xff0c;同样可以做配置管理来使用。 1.1.统一配置管理 当微服务部署的实例越来越多&#xff0c;达到数十、数百时&#xff0c;逐个修改微服务配置就会让人抓狂&#xff0c;而且很容易出错。我们需要一种统一配置管理…

K8S CNI

OCI概念 OCI&#xff0c;Open Container Initiative&#xff0c;开放容器标准&#xff0c;是一个轻量级&#xff0c;开放的治理结构&#xff08;项目&#xff09;&#xff0c;在 Linux 基金会的支持下成立&#xff0c;致力于围绕容器格式和运行时创建开放的行业标准。 OCI 项目…

Unity中的网格创建和曲线变形

Unity中的网格创建和曲线变形 3D贝塞尔曲线变形贝塞尔曲线基础线性公式二次方公式三次方公式 Unity 实现3D贝塞尔曲线变形准备工作脚本概述变量定义 变量解析函数解析 获取所有子节点GetAllChildren 获取所有子节点UpdateBezierBend 控制点更新CalculateBezier Bezier 曲线公式…

JumpServer部署使用

1. 简介 JumpServer 是全球首款开源的堡垒机&#xff0c;使用 GNU GPL v3.0 开源协议&#xff0c;是符合 4A 规范的运维安全审计系统&#xff0c;使用 Python 开发&#xff0c;遵循 Web 2.0 规范&#xff0c;配备了业界领先的 Web Terminal 方案&#xff0c;交互界面美观、用户…

常见的实时操作系统(RTOS)(嵌入式和物联网操作系统)介绍

在嵌入式系统和物联网&#xff08;IoT&#xff09;设备中&#xff0c;实时操作系统&#xff08;RTOS&#xff09;是至关重要的&#xff0c;因为它们负责管理有限的硬件资源&#xff0c;并提供确保任务在特定时间内完成的机制。开源实时操作系统&#xff08;RTOS&#xff09;允许…

【Python】清理conda缓存的常用命令

最近发现磁盘空间不足&#xff0c;很大一部分都被anaconda占据了&#xff0c;下面是一些清除conda缓存的命令 清理所有环境的Anaconda包缓存 删除所有未使用的包以及缓存的索引和临时文件 conda clean --all清理某一特定环境的Anaconda包缓存 conda clean --all -n 环境名清…

离线安装docker、docker-compose、Mysql镜像

离线安装docker docker-compose mysql镜像 一、下载docker docker-compose mysql 镜像文件 1、首先下载docker镜像 博主所用文件版本号&#xff1a; docker-23.0.6.tgz 下载docker 地址 &#xff1a;https://blog.csdn.net/xiaohanshasha/article/details/135489623?spm1001…

Vue前端开发记录(一)

本篇文章中的图片均为深色背景&#xff0c;请于深色模式下观看 说明&#xff1a;本篇文章的内容为vue前端的开发记录&#xff0c;作者在这方面的底蕴有限&#xff0c;所以仅作为参考 文章目录 一、安装配置nodejs,vue二、vue项目目录结构三、前期注意事项0、组件1、数不清的报…