【JWT】jwt实现HS、RS、ES、ED签名与验签

JWT 实现 HSRSESED 签名与验签

签名方式算法密钥类型签名要点验签要点
HSHMAC-SHA256对称密钥- 使用 crypto/hmac 和对称密钥生成 HMAC 签名
- 将 header.payload 作为数据输入
- 使用同一密钥重新计算 HMAC 签名
- 比较计算结果与接收到的签名是否一致
RSRSA-SHA256公钥 + 私钥- 使用 crypto/rsa 生成 RSA 签名
- 私钥签名,输入为 header.payload 的哈希值
- 使用 crypto/rsa 验证 RSA 签名
- 公钥解密签名后,验证是否与输入哈希值匹配
ESECDSA-P256公钥 + 私钥- 使用 crypto/ecdsa 生成 ECDSA 签名
- 签名结果为 (r, s),序列化并编码为 Base64URL
- 使用 crypto/ecdsa 验证签名
- 解析签名为 (r, s),验证其与 header.payload 的哈希匹配
EDEd25519公钥 + 私钥- 使用 crypto/ed25519 私钥直接签名完整的 header.payload 数据
- 签名结果无需额外哈希处理
- 使用 crypto/ed25519 公钥直接验证签名是否匹配完整数据

签名与验签实现重点

  • es算法签名和验签时算法位数必须相同:ES算法在验签时必须严格使用与签名时相同位数的算法进行验证,这一点与其他算法有所不同。(其他算法不必相同) 说明如下:

  • 加密在这里插入图片描述

  • 验签 在这里插入图片描述

  • Base64URL 编码:JWT 的 HeaderPayload 都需编码。

  • 数据输入:签名计算与验证的输入数据始终是 Base64URL(Header) + "." + Base64URL(Payload)

  • 密钥管理:对称密钥 (HS) 要妥善分发,公私钥对 (RS/ES/ED) 要安全存储。


go案例

hs.go

package jwtex

import (
	"github.com/golang-jwt/jwt/v5"
	"log"
)

type HS struct {
	Key        string
	SignMethod HSSignMethod
}

type HSSignMethod string

const (
	HS256 HSSignMethod = "HS256"
	HS384 HSSignMethod = "HS384"
	HS512 HSSignMethod = "HS512"
)

// hs HMAC(Hash-based Message Authentication Code)用的hash-based
func (hs *HS) getSignMethod() *jwt.SigningMethodHMAC {
	// *jwt.SigningMethodHMAC 是 jwt.SigningMethod 接口的具体实现之一。通过返回具体的实现类型,
	// 可以确保你使用的是 HMAC 签名方法,而不是其他类型的签名方法(如 RSA 或 ECDSA)。
	switch hs.SignMethod {
	case HS256:
		return jwt.SigningMethodHS256
	case HS384:
		return jwt.SigningMethodHS384
	case HS512:
		return jwt.SigningMethodHS512
	default:
		return jwt.SigningMethodHS256
	}
}

// Sign 签名
func (hs *HS) Sign(data jwt.Claims) (string, error) {
	token := jwt.NewWithClaims(hs.getSignMethod(), data)
	sign, err := token.SignedString([]byte(hs.Key))
	if err != nil {
		log.Println(err)
		return "", err
	}
	return sign, nil
}

// Verify 验签,获取数据
func (hs *HS) Verify(sign string, data jwt.Claims) error {
	_, err := jwt.ParseWithClaims(sign, data, func(token *jwt.Token) (interface{}, error) {
		return []byte(hs.Key), nil
	})
	return err
}


rsa.go 私钥签名、公钥验证

package jwtex

import (
	"github.com/golang-jwt/jwt/v5"
	"log"
)

type RS struct {
	SignMethod RSSignMethod
	PublicKey  string
	PrivateKey string
}

type RSSignMethod string

const (
	RS256 RSSignMethod = "RS256"
	RS384 RSSignMethod = "RS384"
	RS512 RSSignMethod = "RS512"
)

func (rs *RS) getSignMethod() *jwt.SigningMethodRSA {
	switch rs.SignMethod {
	case RS512:
		return jwt.SigningMethodRS512
	case RS384:
		return jwt.SigningMethodRS384
	case RS256:
		return jwt.SigningMethodRS256
	default:
		return jwt.SigningMethodRS256
	}
}

// Sign 签名	私钥签名、公钥验证
func (rs *RS) Sign(data jwt.Claims) (string, error) {
	token := jwt.NewWithClaims(rs.getSignMethod(), data)
	pKey, err := jwt.ParseRSAPrivateKeyFromPEM([]byte(rs.PrivateKey))
	sign, err := token.SignedString(pKey)
	if err != nil {
		log.Println(err)
		return "", err
	}
	return sign, nil
}

// Verify 验签,获取数据
func (rs *RS) Verify(sign string, data jwt.Claims) error {
	_, err := jwt.ParseWithClaims(sign, data, func(token *jwt.Token) (interface{}, error) {
		return jwt.ParseRSAPublicKeyFromPEM([]byte(rs.PublicKey))
	})
	return err
}


es.go 私钥签名、公钥验证

package jwtex

import (
	"github.com/golang-jwt/jwt/v5"
	"log"
)

type ES struct {
	SignMethod ESSignMethod
	PublicKey  string
	PrivateKey string
}

type ESSignMethod string

const (
	ES256 ESSignMethod = "ES256"
	ES384 ESSignMethod = "ES384"
	ES512 ESSignMethod = "ES512"
)

func (es *ES) getSignMethod() *jwt.SigningMethodECDSA {
	switch es.SignMethod {
	case ES512:
		return jwt.SigningMethodES512
	case ES384:
		return jwt.SigningMethodES384
	case ES256:
		return jwt.SigningMethodES256
	default:
		return jwt.SigningMethodES256
	}
}

// Sign 签名	私钥签名、公钥验证
func (es *ES) Sign(data jwt.Claims) (string, error) {
	token := jwt.NewWithClaims(es.getSignMethod(), data)
	pKey, err := jwt.ParseECPrivateKeyFromPEM([]byte(es.PrivateKey))
	if err != nil {
		log.Println(err)
		return "", err
	}
	sign, err := token.SignedString(pKey)
	if err != nil {
		log.Println(err)
		return "", err
	}
	return sign, nil
}

// Verify 验签,获取数据
func (es *ES) Verify(sign string, data jwt.Claims) error {
	_, err := jwt.ParseWithClaims(sign, data, func(token *jwt.Token) (interface{}, error) {
		return jwt.ParseECPublicKeyFromPEM([]byte(es.PublicKey))
	})
	return err
}


ed.go 私钥签名、公钥验证

package jwtex

import (
	"github.com/golang-jwt/jwt/v5"
	"log"
)

type ED struct {
	PrivateKey string
	PublicKey  string
}

// Sign 签名
func (ed *ED) Sign(data jwt.Claims) (string, error) {
	token := jwt.NewWithClaims(jwt.SigningMethodEdDSA, data)
	pKey, err := jwt.ParseEdPrivateKeyFromPEM([]byte(ed.PrivateKey))
	if err != nil {
		log.Println(err)
		return "", err
	}
	sign, err := token.SignedString(pKey)
	if err != nil {
		log.Println(err)
		return "", err
	}
	return sign, err
}

// Verify 验签,并获取数据
func (ed *ED) Verify(sign string, data jwt.Claims) error {
	_, err := jwt.ParseWithClaims(sign, data, func(token *jwt.Token) (interface{}, error) {
		return jwt.ParseEdPublicKeyFromPEM([]byte(ed.PublicKey))
	})
	return err
}


jwt.go

package jwtex

import (
	"github.com/golang-jwt/jwt/v5"
)

type Data struct {
	Name   string
	Age    int
	Gender int
	jwt.RegisteredClaims
}

type Jwt interface {
	Sing(data jwt.Claims) (string, error)
	Verify(sign string, data jwt.Claims) error
}


https://github.com/0voice

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

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

相关文章

【Bug 记录】el-sub-menu 第一次进入默认不高亮

项目场景: 项目场景:el-sub-menu 第一次进入默认不高亮 问题描述 例如:sub-menu 的 index 后端默认传过来是 number,我们需要手动转为 string,否则会有警告,而且第一次进入 sub-menu 默认不高亮。 解决方…

LLM幻觉(Hallucination)缓解技术综述与展望

LLMs 中的幻觉问题(LLM 幻觉:现象剖析、影响与应对策略)对其可靠性与实用性构成了严重威胁。幻觉现象表现为模型生成的内容与事实严重不符,在医疗、金融、法律等对准确性要求极高的关键领域,可能引发误导性后果&#x…

挖掘机的市场现状和发展前景:全球增长潜力,重塑基础设施建设新篇章

引言:工程机械的心脏,挖掘机的崛起之路 在现代化建设的浪潮中,挖掘机作为工程机械领域的核心设备,正以其强大的作业能力和广泛的应用场景,成为推动全球基础设施建设不可或缺的力量。从高速公路到大型矿场,…

算法每日双题精讲 —— 二分查找(山脉数组的峰顶索引,寻找峰值)

🌟快来参与讨论💬,点赞👍、收藏⭐、分享📤,共创活力社区。 🌟 别再犹豫了!快来订阅我们的算法每日双题精讲专栏,一起踏上算法学习的精彩之旅吧💪 在算法的…

Flutter_学习记录_基本组件的使用记录

1.TextWidge的常用属性 1.1TextAlign: 文本对齐属性 常用的样式有: TextAlign.center 居中TextAlign.left 左对齐TextAlign.right 有对齐 使用案例: body: Center(child: Text(开启 TextWidget 的旅程吧,珠珠, 开启 TextWidget 的旅程吧&a…

二叉树的存储(下)c++

链式存储 我们可以创建两个数组L[N]、r[N]&#xff0c;分别存储i 号结点的左右孩子的编号&#xff0c;这样就可以通过数组下标实现链式访问。 本质上还是孩子表示法&#xff0c;存储的是左右孩子的信息 #include <iostream>using namespace std;const int N 1e6 10; …

基于Docker的Kafka分布式集群

目录 1. 说明 2. 服务器规划 3. docker-compose文件 kafka{i}.yaml kafka-ui.yaml 4. kafka-ui配置集群监控 5. 参数表 6. 测试脚本 生产者-异步生产: AsyncKafkaProducer1.py 消费者-异步消费: AsyncKafkaConsumer1.py 7. 参考 1. 说明 创建一个本地开发环境所需的k…

Linux系统 C/C++编程基础——基于Qt的图形用户界面编程

ℹ️大家好&#xff0c;我是练小杰&#xff0c;今天周四了&#xff0c;距离除夕只有4天了&#xff0c;各位今年卫生都搞完了吗&#xff01;&#x1f606; 本文是接着昨天Linux 系统C/C编程的知识继续讲&#xff0c;基于Qt的图形用户界面编程概念及其命令&#xff0c;后续会不断…

C++11(二)

目录 左值引用与右值引用 左值引用 右值引用 右值与左值交叉引用 移动语义 移动构造 移动赋值 完美转发 本期我们将学习C11中比较重要的一个知识点------右值引用。 左值引用与右值引用 在学习左值引用和右值引用之前&#xff0c;我们得先知道什么是左值&#xff0…

【python】四帧差法实现运动目标检测

四帧差法是一种运动目标检测技术&#xff0c;它通过比较连续四帧图像之间的差异来检测运动物体。这种方法可以在一定的程度上提高检测的准确性。 目录 1 方案 2 实践 ① 代码 ② 效果图 1 方案 具体的步骤如下&#xff1a; ① 读取视频流&#xff1a;使用cv2.VideoCapture…

SpringBoot开发(二)Spring Boot项目构建、Bootstrap基础知识

1. Spring Boot项目构建 1.1. 简介 基于官方网站https://start.spring.io进行项目的创建. 1.1.1. 简介 Spring Boot是基于Spring4框架开发的全新框架&#xff0c;设计目的是简化搭建及开发过程&#xff0c;并不是对Spring功能上的增强&#xff0c;而是提供了一种快速使用Spr…

PMP–一、二、三模–分类–12.采购管理

文章目录 技巧十二、采购管理 一模12.采购管理--3.控制采购--输出--风险登记册--每个被选中的卖方都会带来特殊的风险。随着早期风险的过时以及新风险的出现&#xff0c;在项目执行期间对风险登记册进行变更。 供应商还未开始做&#xff0c;是一个风险&#xff0c;当做风险进行…

栈和队列(C语言)

目录 数据结构之栈 定义 实现方式 基本功能实现 1&#xff09;定义&#xff0c;初始化栈 2&#xff09;入栈 3&#xff09;出栈 4&#xff09;获得栈顶元素 5)获得栈中有效元素个数 6&#xff09;检测栈是否为空 7&#xff09;销毁栈 数据结构之队列 定义 实现方…

B站pwn教程笔记-1

因为没有垃圾处理机制&#xff0c;适合做编译&#xff0c;不会有堵塞 c语言市场占有率还是比较高的。 Windows根据后缀识别文件&#xff0c;linux根据文件头识别 55:16 编译过程 一步&#xff1a;直接gcc编译.c文件 这只是其中的一些步骤 gcc -S 转变为汇编。但其实这时候还…

jQuery小游戏

jQuery小游戏&#xff08;一&#xff09; 嘻嘻&#xff0c;今天我们来写个jquery小游戏吧 首先&#xff0c;我们准备一下写小游戏需要准备的佩饰&#xff0c;如果&#xff1a;图片、音乐、搞怪的小表情 这里我准备了一些游戏中需要涉及到的图片 游戏中使用到的方法 eval() 函…

Batch Normalization学习笔记

文章目录 一、为何引入 Batch Normalization二、具体步骤1、训练阶段2、预测阶段 三、关键代码实现四、补充五、参考文献 一、为何引入 Batch Normalization 现在主流的卷积神经网络几乎都使用了批量归一化&#xff08;Batch Normalization&#xff0c;BN&#xff09;1&#xf…

JavaSec系列 | 动态加载字节码

视频教程在我主页简介或专栏里 目录&#xff1a; 动态加载字节码 字节码 加载远程/本地文件 利用defineClass()直接加载字节码 利用TemplatesImpl加载字节码 动态加载字节码 字节码 Java字节码指的是JVM执行使用的一类指令&#xff0c;通常被存储在.class文件中。 加载远程…

第十四讲 JDBC数据库

1. 什么是JDBC JDBC&#xff08;Java Database Connectivity&#xff0c;Java数据库连接&#xff09;&#xff0c;它是一套用于执行SQL语句的Java API。应用程序可通过这套API连接到关系型数据库&#xff0c;并使用SQL语句来完成对数据库中数据的查询、新增、更新和删除等操作…

JVM面试题解,垃圾回收之“分代回收理论”剖析

一、什么是分代回收 我们会把堆内存中的对象间隔一段时间做一次GC&#xff08;即垃圾回收&#xff09;&#xff0c;但是堆内存很大一块&#xff0c;内存布局分为新生代和老年代、其对象的特点不一样&#xff0c;所以回收的策略也应该各不相同 对于“刚出生”的新对象&#xf…

电脑如何访问手机文件?

手机和电脑已经深深融入了我们的日常生活&#xff0c;无时无刻不在为我们提供服务。除了电脑远程操控电脑外&#xff0c;我们还可以在电脑上轻松地访问Android或iPhone手机上的文件。那么&#xff0c;如何使用电脑远程访问手机上的文件呢&#xff1f; 如何使用电脑访问手机文件…