2.4goweb加解密和jwt

news2025/4/16 3:20:02

MD5的基本实现

1. ​​标准库调用​

Go语言通过crypto/md5包提供MD5算法的实现。核心步骤包括:

  • ​创建哈希对象​​:使用md5.New()生成一个实现了hash.Hash接口的实例。
  • ​写入数据​​:通过Write()方法或io.WriteString()将数据写入哈希对象。
  • ​生成哈希值​​:调用Sum(nil)获取哈希结果,并通过encoding/hex包转换为十六进制字符串。

​示例代码​​:

package main

import (
    "crypto/md5"
    "encoding/hex"
    "fmt"
    "io"
)

func main() {
    h := md5.New()
    io.WriteString(h, "Hello, world!")
    hash := h.Sum(nil)
    fmt.Println(hex.EncodeToString(hash)) // 输出:6cd3556deb0da54bca060b4c39479839
}

此方法支持分块写入数据,适用于大文件处理


2. ​​简化方法​

对于一次性计算,可直接使用md5.Sum()函数:

data := []byte("Hello, world!")
hash := md5.Sum(data)
fmt.Printf("%x\n", hash) // 输出:6cd3556deb0da54bca060b4c39479839

此方法直接返回固定长度的哈希数组(16字节),需手动转换为字符串


 AES对称加解密

package main

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"encoding/base64"
	"errors"
	"fmt"
	"io"
)

func main() {
	// 示例密钥(AES-256需要32字节密钥)
	key := []byte("this-is-a-32-byte-key-1234567890")

	// 原始数据
	plaintext := []byte("今天是2025年4月12日,星期六,农历三月十五")

	fmt.Printf("原始数据: %s\n", plaintext)
	fmt.Printf("密钥: %s\n", key)

	// 加密
	ciphertext, err := AESEncrypt(key, plaintext)
	if err != nil {
		panic(err)
	}

	eb64 := base64.StdEncoding.EncodeToString(ciphertext)
	fmt.Printf("加密结果(Base64): %s\n", eb64)

	db64, _ := base64.StdEncoding.DecodeString(eb64)

	// 解密
	decrypted, err := AESDecrypt(key, db64)
	if err != nil {
		panic(err)
	}

	fmt.Printf("解密结果: %s\n", decrypted)
}

// AESEncrypt 使用AES-256 CBC模式加密数据
func AESEncrypt(key, plaintext []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}

	// PKCS7填充
	plaintext = PKCS7Pad(plaintext, aes.BlockSize)

	// 生成随机IV
	ciphertext := make([]byte, aes.BlockSize+len(plaintext))
	iv := ciphertext[:aes.BlockSize]
	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
		return nil, err
	}

	// 加密
	mode := cipher.NewCBCEncrypter(block, iv)
	mode.CryptBlocks(ciphertext[aes.BlockSize:], plaintext)

	return ciphertext, nil
}

// AESDecrypt 使用AES-256 CBC模式解密数据
func AESDecrypt(key, ciphertext []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}

	if len(ciphertext) < aes.BlockSize {
		return nil, errors.New("ciphertext too short")
	}

	// 提取IV
	iv := ciphertext[:aes.BlockSize]
	ciphertext = ciphertext[aes.BlockSize:]

	// 解密
	mode := cipher.NewCBCDecrypter(block, iv)
	mode.CryptBlocks(ciphertext, ciphertext)

	// 去除PKCS7填充
	return PKCS7Unpad(ciphertext)
}

// PKCS7Pad 实现PKCS7填充
func PKCS7Pad(data []byte, blockSize int) []byte {
	padding := blockSize - len(data)%blockSize
	padText := bytes.Repeat([]byte{byte(padding)}, padding)
	return append(data, padText...)
}

// PKCS7Unpad 去除PKCS7填充
func PKCS7Unpad(data []byte) ([]byte, error) {
	length := len(data)
	if length == 0 {
		return nil, errors.New("empty data")
	}

	padding := int(data[length-1])
	if padding < 1 || padding > aes.BlockSize {
		return nil, errors.New("invalid padding")
	}

	if length < padding {
		return nil, errors.New("data shorter than padding")
	}

	// 检查填充是否有效
	for i := 0; i < padding; i++ {
		if data[length-padding+i] != byte(padding) {
			return nil, errors.New("invalid padding")
		}
	}

	return data[:length-padding], nil
}

关键点说明

  1. 密钥长度
    • AES-256需要32字节(256位)的密钥
    • 示例中使用了简单的字符串密钥,实际应用中应从安全源获取密钥
  2. 初始化向量(IV)
    • 每次加密都生成随机IV,确保相同明文加密结果不同
    • IV不需要保密,但必须不可预测
  3. 填充方案
    • 实现了PKCS7填充,确保数据长度是块大小的倍数
    • 解密后自动去除填充
  4. 安全注意事项
    • 使用crypto/rand生成随机数
    • 解密时严格验证填充有效性
    • 实际应用中应考虑添加消息认证码(MAC)防止篡改

Go语言JWT实现

JWT(JSON Web Token)是一种基于JSON的开放标准(RFC 7519),用于在网络应用间安全地传输信息。其核心是通过签名和声明机制实现无状态身份验证,广泛应用于分布式系统、微服务架构和跨域认证场景

JWT结构组成

Header:算法类型和token类型
{
  "alg": "HS256",
  "typ": "JWT"
}

Payload(载荷)​
  • ​作用​​:携带声明(Claims),包含用户身份信息或其他业务数据。
  • ​声明分类​​:
    • ​Registered Claims​​(标准声明):如iss(签发者)、exp(过期时间)、sub(主题)
    • ​Public Claims​​(自定义声明):需避免与标准声明冲突,如用户角色role
    • ​Private Claims​​(私有声明):业务自定义字段,如用户IDuser_id
  • {
      "sub": "1234567890",
      "name": "John Doe",
      "iat": 1516239022,
      "exp": 1744876800 // 2025年4月12日0时的Unix时间戳 
    }
    Registered Claims​​ 标准声明列表
    声明名称全称类型必填描述
    issIssuerString​签发者标识​​,表示生成JWT的实体(如认证服务器地址)
    subSubjectString​主题标识​​,表示JWT的核心主体(如用户ID或唯一标识)
    audAudienceString​接收方标识​​,指定JWT的预期接收者(如客户端应用ID)
    expExpiration TimeNumber​过期时间​​,Unix时间戳,表示JWT失效时间(必须大于iat
    nbfNot BeforeNumber​生效时间​​,Unix时间戳,表示JWT在此时间前不可用
    iatIssued AtNumber​签发时间​​,Unix时间戳,记录JWT生成时间
    jtiJWT IDString​唯一标识符​​,用于防止重放攻击(建议全局唯一)
Signature:对前两部分的签名
  • 作用​​:验证JWT的完整性和真实性,防止篡改。
  • ​生成方式​​:对HeaderPayload的Base64编码字符串拼接后,使用密钥和算法生成签名。

完整实现示例

安装依赖

go get github.com/golang-jwt/jwt/v5  

代码实现 

package main 
 
import (
	"fmt"
	"time"
	"github.com/golang-jwt/jwt/v5" 
)
 
// 自定义Claims结构体 
type CustomClaims struct {
	UserID   string `json:"user_id"`
	Username string `json:"username"`
	jwt.RegisteredClaims // 内置标准声明(exp, iat, nbf等)
} 
 
var secretKey = []byte("your-256-bit-secret-2025-04-12")
 
func main() {
	// 生成Token 
	tokenString, err := GenerateToken("u10001", "张三")
	if err != nil {
		panic(err)
	}
	fmt.Printf("生成的Token: %s\n", tokenString)
 
	// 验证Token 
	claims, err := ParseToken(tokenString)
	if err != nil {
		panic(err)
	}
	fmt.Printf("解析结果: %+v\n", claims)
}
 
// GenerateToken 生成JWT Token 
func GenerateToken(userID, username string) (string, error) {
    expiration := time.Now().Add(24 * time.Hour)
	claims := CustomClaims{
		UserID:   userID,
		Username: username,
		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(expiration),
            IssuedAt:  jwt.NewNumericDate(time.Now()),
		},
	}
 
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	return token.SignedString(secretKey)
}
 
// ParseToken 解析验证JWT Token 
func ParseToken(tokenString string) (*CustomClaims, error) {
	token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
		}
		return secretKey, nil 
	})
 
	if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid {
		return claims, nil 
	}
	return nil, err 
}

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

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

相关文章

深入解析多表联查(MySQL)

前言 在面试中以及实际开发中&#xff0c;多表联查是每个程序员必备技能&#xff0c;下文通过最简单的学生表和课程表的实例帮大家最快入门多表联查技能。 建立数据表 1. 学生表&#xff08;students&#xff09; 创建学生表 CREATE TABLE students (student_id INT AUTO_…

宇视设备视频平台EasyCVR打造智慧酒店安防体系,筑牢安全防线

一、需求背景 酒店作为人员流动频繁的场所&#xff0c;对安全保障与隐私保护有着极高的要求。为切实维护酒店内部公共区域的安全秩序&#xff0c;24小时不间断视频监控成为必要举措。通常情况下&#xff0c;酒店需在本地部署视频监控系统以供查看&#xff0c;部分连锁酒店还希…

Linux中的文件传输(附加详细实验案例)

一、实验环境的设置 ①该实验需要两台主机&#xff0c;虚拟机名称为 L2 和 L3 &#xff0c;在终端分别更改主机名为 node1 和 node2&#xff0c;在实验过程能够更好分辨。 然后再重新打开终端&#xff0c;主机名便都更改了相应的名称。 ②用 ip a 的命令分别查看两个主机的 …

基于 OpenHarmony 5.0 的星闪轻量型设备应用开发——Ch2 OpenHarmony LiteOS-M 内核应用开发

写在前面&#xff1a; 此篇是系列文章《基于 OpenHarmony5.0 的星闪轻量型设备应用开发》的第 2 章。本篇介绍了如何在 OpenHarmony 5.0 框架下&#xff0c;针对 WS63 进行 LiteOS-M 内核应用工程的开发。 为了方便读者学习&#xff0c;需要OpenHarmony 5.0 WS63 SDK 的小伙伴可…

Linux--线程概念与控制

目录 1. Linux线程概念 1-1 什么是线程 1-2 分⻚式存储管理 1-2-1 虚拟地址和⻚表的由来 1-2-2 物理内存管理 1-2-3 ⻚表 1-2-4 ⻚⽬录结构 1-2-5 两级⻚表的地址转换 1-2-6 缺⻚异常 1-3 线程的优点 1-4 线程的缺点 1-5 线程异常 1-6 线程⽤途 2. Linux进程VS线…

Python | kelvin波的水平空间结构

写在前面 简单记录一下之前想画的一个图&#xff1a; 思路 整体比较简单&#xff0c;两个子图&#xff0c;本质上就是一个带有投影&#xff0c;一个不带投影&#xff0c;通常用在EOF的空间模态和时间序列的绘制中&#xff0c;可以看看之前的几个详细的画法。 Python | El Ni…

【音视频】SDL播放PCM音频

相关API 打开音频设备 int SDLCALL SDL_OpenAudio(SDL_AudioSpec * desired, SDL_AudioSpec * obtained); desired&#xff1a;期望的参数。obtained&#xff1a;实际音频设备的参数&#xff0c;一般情况下设置为NULL即可。 SDL_AudioSpec typedef struct SDL_AudioSpec { i…

BERT - Bert模型框架复现

本节将实现一个基于Transformer架构的BERT模型。 1. MultiHeadAttention 类 这个类实现了多头自注意力机制&#xff08;Multi-Head Self-Attention&#xff09;&#xff0c;是Transformer架构的核心部分。 在前几篇文章中均有讲解&#xff0c;直接上代码 class MultiHeadAtt…

docker创建容器添加启动--restart选项

一、通过 Docker 命令直接修改已启动的容器&#xff08;推荐-已验证&#xff09; 操作步骤&#xff1a; 1.执行更新命令&#xff1a; docker update --restartalways <容器名或ID>此命令会将容器的重启策略调整为 always&#xff08;无论容器以何种状态退出&#xff0…

一文读懂WPF系列之常用控件以及样式

WPF控件 控件分类概览常用控件常用控件代码示例和效果 样式与模板应用样式定义​​方式行内样式​​页面/窗口级资源样式&#xff08;Local Resource&#xff09;应用程序全局资源独立资源字典&#xff08;ResourceDictionary&#xff09;控件模板&#xff08;ControlTemplate&…

【双指针】专题:LeetCode 283题解——移动零

移动零 一、题目链接二、题目三、题目解析四、算法原理两个指针的作用以及三个区间总结 五、与快速排序的联系六、编写代码七、时间复杂度、空间复杂度 一、题目链接 移动零 二、题目 三、题目解析 “保持非零元素的相对顺序”&#xff0c;比如&#xff0c;示例1中非零元素1…

2025蓝桥杯JavaB组

说明 博主自己水平有限&#xff0c;而且答案也不一定对&#xff0c;下面代码和思路仅作分享。我只把我考场上做了的写出来了&#xff0c;有什么问题欢迎评论区交流。 A&#xff1a;逃离高塔 思路&#xff1a; 由于有了去年的经验&#xff0c;所以一上来我就是找规律&#xf…

SQL学习--基础语法学习

SQL和excle对比 学习目标 单表查询 项目背景 SQL 练习环境 SQL Online Compiler - Next gen SQL Editor 商品信息表&#xff1a;https://study-zhibo.oss-cn-shanghai.aliyuncs.com/test/%E5%95%86%E5%93%81%E4%BF%A1%E6%81%AF%E8%A1%A8.csv 订单明细表&#xff1a;https://…

MATLAB2022b安装

1 从百度网盘下载MATLAB2022b&#xff0c;下载完成后解压到某个文件夹&#xff1b; 链接: MATLAB2022b 提取码: 6666 2 打开解压后的文件夹&#xff0c;进入setup文件夹&#xff0c;双击打开“setup.exe”文件&#xff1b; 3 在弹出窗口中选择“高级选项”-->“我有文件安…

架构总览怎么写,才算工业级?

📈系统架构文档是整个项目最重要的起点,但很多人第一章就“写穿了”: 不是写得太细,就是没有重点。想要写出高质量、能协作、能传承的架构文档,这一篇会告诉你应该怎么做—— ✅ 架构总览的终极目标 明确边界、定义角色、画清数据流 别讲执行细节,别深入函数调用。 ✅ 架…

Datawhale 入驻 GitCode:以开源力量推动 AI 教育公平与创新

在 AI 技术深度重塑教育生态的今天&#xff0c;国内首个 AI 开源学习社区 —— Datawhale 正式加入 GitCode 开源平台&#xff01;作为覆盖全球 3000 高校、培养超百万 AI 人才的创新社区&#xff0c;Datawhale 将通过开源协作模式&#xff0c;为人工智能教育公平注入新动能&a…

ChatDBA:一个基于AI的智能数据库助手

今天给大家介绍一个基于 AI 大语言模型实现数据库故障诊断的智能助手&#xff1a;ChatDBA。 ChatDBA 是由上海爱可生信息技术股份有限公司开发&#xff0c;通过对话交互&#xff0c;提供数据库故障诊断、专业知识学习、SQL 生成和优化等功能&#xff0c;旨在提升 DBA 工作效率。…

MacOS中的鼠标、触控板的设置研究

一、背景和写这篇文章的原因 想搞清楚和配置好鼠标&#xff0c;比如解决好为什么我的滚动那么难用&#xff1f;怎么设置滚轮的方向跟windows相同&#xff1f;调整双击速度&#xff0c;调整鼠标滚轮左右拨动的"冷却时间"。 二、各种设置之详细解释 1. MacOS设置 -&…

asp.net core 项目发布到 IIS 服务器

目录 一、VS2022 发布 二、设置IIS服务 三、配置IIS管理器 &#xff08;一&#xff09;打开IIS管理器 &#xff08;二&#xff09;添加站台 &#xff08;三&#xff09;配置应用程式集区 四、安装ASP.NET Core Hosting Bundle 五、设定IIS的日志位置 六、测试 一、VS2…

【Nodebb系列】Nodebb笔记写入方案

NodeBB写入方案 前言 最近在整理以前记录的碎片笔记&#xff0c;想把它们汇总到NodeBB中&#xff0c;方便管理和浏览。但是笔记内容有点多&#xff0c;并且用发帖的形式写到NodeBB中会丢失时间信息&#xff0c;因此整理了一套NodeBB写入方案&#xff0c;大致流程如下&#xf…