当前位置: 首页 > news >正文

2.4goweb加解密和jwt

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 
}

相关文章:

  • 物美“外贸转内销”极速绿色通道正式开启
  • ubuntu20.04 openvino的yolov8推理(nncf量化)
  • 【LINUX】学习宝典
  • spring security oauth2.0的四种模式
  • 二战蓝桥杯所感
  • Manus:开启智能新时代的通用型 AI Agent
  • ckeditor4.22版本 ckfinder php8版本下,上传提示400的问题
  • service和endpoints是如何关联的?
  • 信号FFT分析
  • 解决VS2022中scanf报错C4996
  • 创建小红书批量发布笔记RPA机器人并且添加卡密管理系统
  • Python map函数介绍
  • 快速搭建WordPress网站的主题
  • YOLOv11 解读
  • Python与去中心化存储:从理论到实战的全景指南【无标题】
  • Python 的 re.split()
  • 十二、C++速通秘籍—静态库,动态库
  • HBuilder创建项目步骤
  • 虎跃办公AI:重构智能办公的「模型交响乐团」
  • conda如何安装和运行jupyter
  • 企信网企业信息查询平台官网/上海百度推广优化排名
  • 使用unity做网站/如何网络营销
  • 网站备案在哪个网/百度站长之家
  • 平面设计图用什么软件/谷歌seo一个月费用需要2万吗
  • 文明网站建设方案/怎样搭建网站
  • 无锡网站建设设计公司/深圳新闻最新事件