jwt 介绍

news2025/1/23 10:46:30

目录

  • 1,jwt 的出现
    • 问题
  • 2,jwt 介绍
  • 3,jwt 令牌的组成
    • 3.1,header
    • 3.2,payload
    • 3.3,signature
  • 4,验证
  • 5,总结

身份验证相关内容:
浏览器 cookie 的原理(详)
session 原理

1,jwt 的出现

在浏览器 cookie 的原理(详)这篇文章中介绍了身份验证的步骤:

在这里插入图片描述

简单来说,如果身份验证通过 session 完成,那【出入证】就是一个 cookie 信息,内容是 sessionId。但还有其他的问题需要解决:

问题

随着前后端分离的发展,一个产品的终端可能不止是浏览器,还有桌面应用、智能家居等设备。

在这里插入图片描述
通过上图中可以看到:这些设备都会和同一个服务器通信,一般都是 http 协议。

通常不同的产品线会有自己的服务器,产品内部数据一般和自己的服务器交互。但中心服务器仍有存在的必要,因为产品之间总会有数据需要共享。

这个中心服务器至少承担着认证和授权的功能,比如登录:各种设备发送消息到中心服务器,中心服务器响应一个【出入证】(令牌信息)。

问题来了:其他的设备还能使用 cookie 传递令牌信息吗?

虽然 cookie 简单来说就是一个消息头,但浏览器有完善的管理机制:比如自动保存和自动发送,还有相应的安全机制等。但其他设备上的 cookie 机制就需要手动处理了。

jwt 的出现就是为了解决这个问题。

2,jwt 介绍

全称为 json web token,目的:为不同的终端设备提供统一的、安全的令牌格式。

在这里插入图片描述
令牌信息在传输时就是一个字符串而已,而 jwt 是令牌格式。这个字符串可以简单理解为:对一些特殊信息做了编码和加密,来达到身份验证的目的。

所以对这个字符串来说,

  • 在客户端的存储位置没有限制,放到 cookielocalStorage、pc 文件、手机文件中都可以。
  • 传输方式也没有限制。一般来说,会使用消息头来传输它:

比如登录成功后,服务器可以给客户端响应一个 jwt令牌:

POST /api/login HTTP/1.1 200 OK
...
set-cookie: token=jwt令牌
authorization: bearer jwt令牌
...

{..., token:jwt令牌}

它可以出现在响应的任何位置,或是同时出现在多个位置。
以上面的响应为例,就是为了充分利用浏览器的 cookie 机制,同时为了照顾其他设备,所以也出现在了响应头 authorization 和响应体中。

虽然没有明确的要求应该如何附带到请求中,但通常都会如下的格式(OAuth2附带 token 的一种规范格式):

GET /api/resources HTTP/1.1
...
authorization: bearer jwt令牌
...

整体交互流程:

在这里插入图片描述

3,jwt 令牌的组成

为了保证令牌的安全性,jwt 令牌由3个部分组成:

  1. header,头部,记录令牌的类型和签名算法。
  2. payload,负载,记录主体信息,比如用户信息。
  3. signature,签名,按头部的签名算法对整个令牌签名,作用:保证令牌不被伪造和篡改。

完整格式为 header.payload.signature。举例:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJteW5hbWUiLCJpYXQiOiIxNzAzNzc2NjM3In0._UuiFQ-rF8DZdheGE79LA46nfACrn2IiFPckUay7lQI

3.1,header

格式为 json 对象:

{
  "alg":"HS256",
  "typ":"JWT"
}
  1. alg 签名算法,默认是 HMAC SHA256 写成 HS256(对称加密算法);也可以使用 RS256(非对称加密算法)。
  2. typ 令牌类型,固定为 JWT

接着将 json 对象使用 base64 url 编码。

base64 url 不是加密算法,而是一种编码格式,它是在 base64 编码的基础上对 =+/ 这3个字符做特殊处理(=被省略,+替换为 -/ 替换为 _),因为 jwt 可能也会在 url 中传输。
base64 是使用64个可打印字符来表示一个二进制数据。

nodejs 需要借助第三方库实现,比如 base64url:

const base64url = require("base64url");

const a = base64url.encode(
  JSON.stringify({
    alg: "HS256",
    typ: "JWT",
  })
);
console.log(a); // eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

const b = base64url.decode("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9");
console.log(b);

3.2,payload

jwt 的主体信息,也是一个 json 对象,包含以下内容:

{
  "ss""发行者", // 可以是公司名字,也可以是服务名称
  "iat""发布时间",
  "exp""到期时间",
  "sub""主题", // 该 jwt 的作用
  "aud""受众", // 发放给哪个终端的,可以是终端类型,也可以是用户名称
  "nbf""在此之前不可用", // 一个时间点,在该时间点到达之前,这个令牌是不可用的
  "jti""JWT ID" // jwt的唯一编号,主要是为了防止重放攻击(在某些场景下,用户使用之前的令牌发送到服务器,被服务器正确的识别,从而导致不可预期的行为发生)
}

以上内容只是一个规范,都是可选的。设置了也需要之后验证 jwt 令牌时手动处理才能发挥作用。

而我们可以把需要的信息加进去,比如用户 id 等等。比如:

{
  "foo": "myname", // 自定义信息
  "iat": "1703776637" // 规范的信息
}

同样也需要使用 base64url 编码:

// base64url 编码
const base64url = require("base64url");
const a = base64url.encode(
  JSON.stringify({
    foo: "myname",
    iat: "1703776637",
  })
);
// eyJmb28iOiJteW5hbWUiLCJpYXQiOiIxNzAzNzc2NjM3In0

注意,浏览器提供的 window.btoa 函数只是 base64 编码,并不是base64 url 编码!不会对 =+/ 这3个字符做特殊处理。

window.btoa(JSON.stringify({
  "foo":"myname",
  "iat":"1703776637"
}))
// 'eyJmb28iOiJteW5hbWUiLCJpYXQiOiIxNzAzNzc2NjM3In0='

// 但都可被正常解码,下面2个结果相同
window.atob('eyJmb28iOiJteW5hbWUiLCJpYXQiOiIxNzAzNzc2NjM3In0=')
window.atob('eyJmb28iOiJteW5hbWUiLCJpYXQiOiIxNzAzNzc2NjM3In0')

header 和 payload 都算是明文传输的。所以不要将敏感信息放到 payload 中

3.3,signature

这部分保证了 jwt 不会被篡改或伪造。

生成步骤:将 header 和 payload 的编码结果,使用 header 中指定的加密算法进行加密。

// 上面 header 的编码结果 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
// 上面 payload 的编码结果 eyJmb28iOiJteW5hbWUiLCJpYXQiOiIxNzAzNzc2NjM3In0
const crypto = require("crypto");

function HS256(header, playload) {
  const hmac = crypto.createHmac("sha256", "mykey"); // 创建加密对象,且指定秘钥为 mykey
  hmac.update(`${header}.${playload}`); // 将数据放入加密对象
  return hmac.digest("base64url"); // 编码为 base64url 
}

HS256("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9", "eyJmb28iOiJteW5hbWUiLCJpYXQiOiIxNzAzNzc2NjM3In0")
// _UuiFQ-rF8DZdheGE79LA46nfACrn2IiFPckUay7lQI

最终将这3部分拼接在一起,得到完整的 jwt:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJteW5hbWUiLCJpYXQiOiIxNzAzNzc2NjM3In0._UuiFQ-rF8DZdheGE79LA46nfACrn2IiFPckUay7lQI

node-hmac.digest 参考

4,验证

因为签名使用的秘钥会保存在服务器,所以客户端无法伪造签名来篡改 jwt。

服务器拿到客户端回传的 jwt 之后,除了验证相同之外(比如payload信息被篡改),还需要验证是否过期,受众是否还满足要求等。

最终整体验证流程:

在这里插入图片描述

5,总结

  • jwt本质上是一种令牌格式。它和终端设备无关,同样和服务器无关,甚至与如何传输无关,它只是规范了令牌的格式而已。
  • jwt由三部分组成:header、payload、signature,主体信息在payload。
  • jwt难以被篡改和伪造。这是因为有第三部分的签名存在。所以在秘钥不泄露的前提下,一个验证通过的 jwt token 是值得被信任的。

以上。

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

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

相关文章

计算机视觉技术-锚框

目标检测算法通常会在输入图像中采样大量的区域,然后判断这些区域中是否包含我们感兴趣的目标,并调整区域边界从而更准确地预测目标的真实边界框(ground-truth bounding box)。 不同的模型使用的区域采样方法可能不同。 这里我们介…

蓝牙物联网移动硬件数据传输系统解决方案

随着传感器技术、网络技术和数据传输技术的不断发展,人们对智能设备的需求日渐增强,利用传感器技术可以对周围环境进行准确和全面的感知,获取到实时信息,从而在网络中进行传输和共享,再通过服务器对各种数据进行保存、分析和挖掘等…

Transformer(seq2seq、self-attention)学习笔记

在self-attention 基础上记录一篇Transformer学习笔记 Transformer的网络结构EncoderDecoder 模型训练与评估 Transformer的网络结构 Transformer是一种seq2seq 模型。输入一个序列,经过encoder、decoder输出结果也是一个序列,输出序列的长度由模型决定…

乡村北斗预警预报应急通信调度方案

根据《中共中央国务院关于切实加强农业基础建设进一步促进农业发展农民增收的若干意见》(中发[2008]1号)等文件要求,要健全农业气象服务体系和农村气象灾害防御体系,充分发挥气象服务“三农”的重要作用。 随着中国北斗导航卫星系…

Spark应用程序的结构与驱动程序

Apache Spark是一个强大的分布式计算框架,用于处理大规模数据。了解Spark应用程序的结构和驱动程序是构建高效应用的关键。本文将深入探讨Spark应用程序的组成部分,以及如何编写一个Spark驱动程序来处理数据和执行计算。 Spark应用程序的结构 Spark应用…

CDN:内容分发的高速公路(上)

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云…

如何拍摄好VR全景图片,VR全景图片后期处理有什么技巧

引言: VR全景图片是一种以全景视角呈现场景的图片,通过VR技术可以将用户带入虚拟的环境中,给人一种身临其境的感觉,那么如何才能更好的制作让人满意的全景图片呢? 一.如何拍摄好VR全景图片 1.选择合适的拍…

Java虚拟机中的垃圾回收

2 垃圾回收 2.1 判断一个对象是否可回收 2.1.1 引用计数法 如果一个对象被另一个对象引用,那么它的引用计数加一,如果那个对象不再引用它了,那么引用计数减一。当引用计数为 0 时,该对象就应该被垃圾回收了。 但是下面这种互相…

Linux自己的应用商店yum

💫Linux系统如何安装软件 在Linux系统中我们可以通过多种方式安装软件,常见方式有以下三种:   1.源代码安装   2.rpm包安装   3.使用yum软件包管理器安装   早期人们通过下载软件源代码,然后再经过交叉编译等一系列工作下…

Vue学习day_03

普通组件的注册 局部注册: 创建一个components的文件夹 在里面写上对应的.vue文件 在对应的vue里面写上对应的3部分 template写上对应的核心代码 盒子等 style 写上对应的css修饰 在App.vue里面进行引用 import 导包 格式是 import 起个名字 from 位置 在写一个component…

【连接池】-从源码到适配(下),使用dynamic-datasource导致连接池没生效(升级版本)

写在前面 书接上文,连接池没生效,启用了一个什么默认的连接池。具体是什么,一起来看看源码吧。 目录 写在前面一、问题描述二、本地调试三、升级dynamic-datasource四、新的问题(一)数据源初始化问题(二&am…

mysql树查询和时间段查询

本文目录 文章目录 案例1:MySQL树形结构查询案例2:MySQL查询一段时间内的所有日期 摘要 案例1:MySQL树形结构查询 在页面开发过程中,如图一所示的树形控件很常见,而大多数情况下,树形控件中需要显示的数据…

AI赋能金融创新:技术驱动的未来金融革命

人工智能(AI)作为一种技术手段,正逐渐改变金融行业的方方面面。从风险管理到客户体验,从交易执行到反欺诈,AI带来了许多创新和机遇。本文将探讨AI在金融领域的应用和其赋能的金融创新。 金融领域一直以来都面临着复杂的…

钡铼技术集IO数据采集可编程逻辑控制PLC无线4G环保物联网关

背景 数据采集传输对于环保企业进行分析和决策是十分重要的,而实时数据采集更能提升环保生产的执行力度,从而采取到更加及时高效的措施。因此实时数据采集RTU成为环保企业的必备产品之一。 产品介绍 在推进环保行业物联网升级过程中,环保RTU在…

Spark作业的调度与执行流程

Apache Spark是一个分布式计算框架,用于处理大规模数据。了解Spark作业的调度与执行流程是构建高效分布式应用程序的关键。本文将深入探讨Spark作业的组成部分、调度过程以及执行流程,并提供丰富的示例代码来帮助大家更好地理解这些概念。 Spark作业的组…

C语言编程入门 – 编写第一个Hello, world程序

C语言编程入门 – 编写第一个Hello, world程序 C Programming Entry - Write the first application called “Hello, world!” By JacksonML C语言编程很容易! 本文开始,将带领你走过C语言编程之旅,通过实例使你对她颇感兴趣,一…

数据库一般会采取什么样的优化方法?

数据库一般会采取什么样的优化方法? 1、选取适合的字段属性 为了获取更好的性能,可以将表中的字段宽度设得尽可能小。 尽量把字段设置成not null 执行查询的时候,数据库不用去比较null值。 对某些省份或者性别字段,将他们定义为e…

关于IDEA中Git版本回滚整理

Git分区理解 git的版本回滚本质上就是回滚不同的分区,所以咱们有必要简单了解一下git的分区。git在本地有三大分区:暂存区、工作区、版本库。 暂存区: add后的代码,绿色。 **工作区:**正在编写,还未add的部分&#…

stm32中的i2c协议

stm32中I2C 文章目录 stm32中I2CI2C 协议简介I2C物理层协议层I2C基本读写过程 **通讯的起始和停止信号****数据有效性****地址及数据方向****响应** STM32的I2C特性及架构**STM32** **的** I2C外设简介STM32 的 I 2C 架构剖析通讯引脚 通讯过程主发送器主接收器 I2C初始化结构体…

Livox-Mid-360 固态激光雷达ROS格式数据分析

前言: Livox-Mid-360 官方采用livox_ros_driver2ROS功能包发布ROS格式的数据,livox_ros_driver2可以把Livox原始雷达数据转化成ROS格式并以话题的形式发布出去。 下面列举一些雷达的基本概念: 点云帧:雷达驱动每次向外发送的一…