golang jwt(hs,es,rs,ed)密钥生成、加签验签案例

news2024/11/21 0:20:08

golang JWT加签算法及使用案例

JWT原理

查看官方lib库
官方lib库

选择go语言

数据结构定义

secret.go

package secret

const KEY_PATH = "keys"

type OutSecret struct {
    Secret string   // 哈希签名
    PublicKeyFile string
    PrivateKeyFile string
}
// 密钥生成
type Secret interface {
    // 密钥信息可能是字符串,也可能是公钥+私钥
    Generate() (*OutSecret, error)
}

x509封装

x509PemGen.go

package secret

import (
    "encoding/pem"
    "log"
    "os"
)

func X509PemGenerate(privateKey []byte, publicKey[]byte, priName string, pubName string) error{
    // 公钥 私钥写文件

    privateBlock := &pem.Block{
        Type: "PRIVATE KEY",
        Bytes: privateKey,
    }

    publicBlock := &pem.Block{
        Type: "PUBLIC KEY",
        Bytes: publicKey,
    }

    privateKeyFileName := priName
    publicKeyFileName := pubName

    privateFile, err := os.OpenFile(privateKeyFileName, os.O_CREATE|os.O_WRONLY, 0644)

    if err != nil {
        log.Println(err)
        return err
    }

    defer privateFile.Close()

    pem.Encode(privateFile, privateBlock)

    publicFile, err := os.OpenFile(publicKeyFileName, os.O_CREATE|os.O_WRONLY, 0644)

    if err != nil {
        log.Println(err)
        return err
    }

    defer publicFile.Close()

    pem.Encode(publicFile, publicBlock)
    return nil
}
HS、RS、ES、ED签名密钥生成
HS签名密钥生成

HS(HMAC-SHA)是一种对称加密算法,它需要一个共享密钥来进行加解密操作。在JWT中,我们可以使用HS256、HS384和HS512三种不同长度的哈希值作为加密算法。其密钥可以直接用一个随机字符串即可

package secret

import (
    "encoding/hex"
    "math/rand"
    "time"
)

// HS的密钥可以是一个随机的字符串
type HsGenerator struct {
    Length int

}


func (hs *HsGenerator) Generate() (*OutSecret, error) {
    out := OutSecret{}
    length := 32

    if hs.Length > 0 {
        length = hs.Length
    }

    // 随机生成字符串
    rand.Seed(time.Now().UnixNano())

    b := make([]byte, length)

    rand.Read(b)
    out.Secret = hex.EncodeToString(b)[:length]

    return &out, nil
}
RS签名密钥生成

RS(RSA-SHA)是一种非对称加密算法,它需要一个公钥和一个私钥来进行加解密操作。在JWT中,我们可以使用RS256、RS384和RS512三种不同长度的RSA密钥作为加密算法

RSA基于一个十分简单的数论事实:将两个大素数相乘十分容易,但想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥,即公钥,而两个大素数组合成私钥

在这里插入图片描述

案例

package secret

import (
    "crypto/rand"
    "crypto/rsa"
    "crypto/x509"
    _ "encoding/hex"
    "log"
    _ "time"
)

//RSA,生成公钥私钥文件,可以通过openSSL生成也可以

type RsGenerator struct {

}


func (rs *RsGenerator) Generate() (*OutSecret, error) {
    out := OutSecret{}

    var err error


    // 生成密钥对,包含公钥
    privateKey, err := rsa.GenerateKey(rand.Reader, 1024)

    if err != nil {
        log.Println(err)
        return nil, err
    }

    // x509格式封装

    x509PrivateKey,err := x509.MarshalPKCS8PrivateKey(privateKey)  // 传入的是指针类型

    if err != nil {
        log.Println(err)
        return nil, err
    }
    //公钥封装
    x509PublicKey, err := x509.MarshalPKIXPublicKey(&privateKey.PublicKey) // 传入的是指针类型

    if err != nil {
        log.Println(err)
        return nil, err
    }

    // 公钥 私钥写文件

    privateKeyFileName := KEY_PATH + "/rs/private.pem"
    publicKeyFileName := KEY_PATH + "/rs/public.pem"
    err = X509PemGenerate(x509PrivateKey, x509PublicKey, privateKeyFileName, publicKeyFileName)
    if err != nil {
        return nil, err
    }
    out.PrivateKeyFile = privateKeyFileName
    out.PublicKeyFile = publicKeyFileName
    return &out, err
}
ES签名密钥生成

ES(Elliptic Curve Digital Signature Algorithm)是一种基于椭圆曲线密码学的非对称加密算法。在JWT中,我们可以使用ES256、ES384和ES512三种不同长度的ECDSA(Elliptic Curve Digital Signature Algorithm)曲线作为加密算法。不同长度对应的算法不同,而RSA对应的算法是一样的

案例

package secret

import (
    "crypto/ecdsa"
    "crypto/elliptic"
    "crypto/rand"
    "crypto/x509"
    "log"
)

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

type ESSignMethod string

// 椭圆曲线加密算法,每个长度的密钥对都不一样(采用不通的椭圆曲线算法),RSA的则是一样的
type ESGenerator struct {
    SignMethod ESSignMethod
}

func (es * ESGenerator) getCurve() elliptic.Curve{
    switch es.SignMethod {
    case ES256:
        return elliptic.P256()
    case ES384:
        return elliptic.P384()
    case ES512:
        return elliptic.P521()
    }
    return elliptic.P256()
}


func (es *ESGenerator) Generate() (*OutSecret, error) {
    out := OutSecret{}

    privateKey, err := ecdsa.GenerateKey(es.getCurve(), rand.Reader)

    if err != nil {
        log.Println(err)
        return nil, err
    }

    // x509格式封装

    x509PrivateKey,err := x509.MarshalPKCS8PrivateKey(privateKey)  // 传入的是指针类型

    if err != nil {
        log.Println(err)
        return nil, err
    }
    //公钥封装
    x509PublicKey, err := x509.MarshalPKIXPublicKey(&privateKey.PublicKey) // 传入的是指针类型

    if err != nil {
        log.Println(err)
        return nil, err
    }

    // 公钥 私钥写文件

    privateKeyFileName := KEY_PATH + "/es/private.pem"
    publicKeyFileName := KEY_PATH + "/es/public.pem"

    err = X509PemGenerate(x509PrivateKey, x509PublicKey, privateKeyFileName, publicKeyFileName)
    if err != nil {
        return nil, err
    }

    out.PrivateKeyFile = privateKeyFileName
    out.PublicKeyFile = publicKeyFileName
    return &out, err
}


ED签名密钥生成

ED(Edwards-curve Digital Signature Algorithm)是一种基于Edwards曲线密码学的非对称加密算法,在JWT中,我们可以使用ED25519和ED448两种不同长度的Edwards曲线作为加密算法。

案例

package secret

import (
    "crypto/ed25519"
    "crypto/rand"
    "crypto/x509"
    "log"
    "os"
)

// 扭曲爱德华曲线


//RSA,生成公钥私钥文件,可以通过openSSL生成也可以

type EdGenerator struct {

}


func (ed *EdGenerator) Generate() (*OutSecret, error) {
    out := OutSecret{}

    var err error

    publicKey, privateKey, err := ed25519.GenerateKey(rand.Reader)

    if err != nil {
        log.Println(err)
        return nil, err
    }


    // x509格式封装

    x509PrivateKey,err := x509.MarshalPKCS8PrivateKey(privateKey)

    if err != nil {
        log.Println(err)
        return nil, err
    }
    //公钥封装
    x509PublicKey, err := x509.MarshalPKIXPublicKey(publicKey)

    if err != nil {
        log.Println(err)
        return nil, err
    }


    privateKeyFileName := KEY_PATH + "/ed/private.pem"
    publicKeyFileName := KEY_PATH + "/ed/public.pem"

    privateFile, err := os.OpenFile(privateKeyFileName, os.O_CREATE|os.O_WRONLY, 0644)

    if err != nil {
        log.Println(err)
        return nil, err
    }

    defer privateFile.Close()

    err = X509PemGenerate(x509PrivateKey, x509PublicKey, privateKeyFileName, publicKeyFileName)
    if err != nil {
        return nil, err
    }

    out.PrivateKeyFile = privateKeyFileName
    out.PublicKeyFile = publicKeyFileName
    return &out, err
}
HS、RS、ES、ED加签与验签

有了密钥对,现在看他们在JWT中如何加签验签

测试数据结构定义

package jwtex

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

type Data struct {
    // 自定义字段
    Name   string
    Age    int
    Gender int
    // 规定字段
    jwt.RegisteredClaims
}

func (d Data) Valid() error {
    return nil
}

// 可以自定义实现里面的Valid接口

type Jwt interface {
    // Sign 签名
    Sign(data jwt.Claims) (string, error)
    // Verify 验签
    Verify(sign string, data jwt.Claims) error
}

HS加签验签
package jwtex

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


type HS struct {
    Key string
    SignMethod HSSignMethod
}

type HSSignMethod string

const (
    HS256 HSSignMethod = "HS256"
    HS384 HSSignMethod = "HS384"
    HS512 HSSignMethod = "HS512"
)
func (hs *HS)getMethod() *jwt.SigningMethodHMAC{
    switch hs.SignMethod {
    case HS256:
        return jwt.SigningMethodHS256
    case HS384:
        return jwt.SigningMethodHS384
    case HS512:
        return jwt.SigningMethodHS512
    }
    return jwt.SigningMethodHS256
}


// 签名
func (hs *HS)Sign(data jwt.Claims) (string, error) {
    token := jwt.NewWithClaims(hs.getMethod(), data)

    sign, err := token.SignedString([]byte(hs.Key))

    if err != nil {
        log.Println(err)
        return "", err
    }
    return sign, nil
}

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

    return err
}
RS加签验签

RS 的密钥公钥可以使用不同的rsa长度算法进行加签验签

package jwtex

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

type RS struct {
    SignMethod RSSignMethod
    // 密钥对
    PrivateKey string
    PublicKey string
}

type RSSignMethod string


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

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

func (rs *RS)Sign(data jwt.Claims) (string, error) {
    token := jwt.NewWithClaims(rs.getMethod(), data)

    // 私钥
    pKey, err := jwt.ParseRSAPrivateKeyFromPEM([]byte(rs.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

}

func (rs *RS)Verify(sign string, data jwt.Claims) error {
    // keyFunc是提供密钥的函数
    // 公钥解密
    _, err := jwt.ParseWithClaims(sign, data, func(token *jwt.Token) (interface{}, error) {
        return jwt.ParseRSAPublicKeyFromPEM([]byte(rs.PublicKey))
    })

    return err
}

ES加签验签

ES生成的密钥和公钥使用的什么算法,加签验签的时候就要用什么算法(ES256、ES384、ES512)

package jwtex

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

type ES struct {
    SignMethod ESSignMethod
    // 密钥对
    PrivateKey string
    PublicKey string
}

type ESSignMethod string


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

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

func (es *ES)Sign(data jwt.Claims) (string, error) {
    token := jwt.NewWithClaims(es.getMethod(), 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

}

func (es *ES)Verify(sign string, data jwt.Claims) error {
    // keyFunc是提供密钥的函数
    // 公钥解密
    _, err := jwt.ParseWithClaims(sign, data, func(token *jwt.Token) (interface{}, error) {
        return jwt.ParseECPublicKeyFromPEM([]byte(es.PublicKey))
    })

    return err
}

ED加签验签

package jwtex

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

type ED struct {
    // 密钥对
    PrivateKey string
    PublicKey string
}

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, nil

}

func (ed *ED)Verify(sign string, data jwt.Claims) error {
    // keyFunc是提供密钥的函数
    // 公钥解密
    _, err := jwt.ParseWithClaims(sign, data, func(token *jwt.Token) (interface{}, error) {
        return jwt.ParseEdPublicKeyFromPEM([]byte(ed.PublicKey))
    })

    return err
}


代码中体现的基本上只是加签验签算法的不同。

案例测试

使用前面的生成的密钥

package main

import (
    "fmt"
    "github.com/golang-jwt/jwt/v4"
    "jwt-practice/jwtex"
    "jwt-practice/secret"
    "log"
    "os"
    "time"
)



func main() {
    //GenerateKeys()
    //HS加签验签
    data := &jwtex.Data{
        Name: "yuan",
        Age: 11,
        Gender: 2,
        RegisteredClaims: jwt.RegisteredClaims{
            ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour)),
            IssuedAt: jwt.NewNumericDate(time.Now()),  //签发时间
            NotBefore: jwt.NewNumericDate(time.Now()), // 生效时间
        },
    }
    hs := jwtex.HS{
        Key: "123456",
        SignMethod: jwtex.HS384,
    }
    sign, err := hs.Sign(data)
    if err != nil {
        return
    }
    fmt.Println("hs sign:", sign)

    outData := &jwtex.Data{}
    err = hs.Verify(sign, outData)
    if err != nil {
        return
    }
    fmt.Println("hs verify:", outData)

    // jwt是不加密的,下面解一下data字段数据
    /*
    bytes, _:= base64.URLEncoding.DecodeString("eyJOYW1lIjoieXVhbiIsIkFnZSI6MTEsIkdlbmRlciI6MiwiRXhwaXJlc0F0IjoiMjAyMy0xMC0xMVQyMjoyMjoyOS4yOTMzODg0KzA4OjAwIn0")
    fmt.Println(string(bytes))
    */
    fmt.Println("------------------")
    //RS加签验签
    privateKey, _ := os.ReadFile("keys/rs/private.pem")
    publicKey, _ := os.ReadFile("keys/rs/public.pem")

    rs := jwtex.RS{
        SignMethod: jwtex.RS512,
        PrivateKey: string(privateKey),
        PublicKey: string(publicKey),
    }
    sign, err = rs.Sign(data)
    if err != nil {
        return
    }
    fmt.Println("rs sign:", sign)

    outData = &jwtex.Data{}
    err = rs.Verify(sign, outData)
    if err != nil {
        log.Println(err)
        return
    }
    fmt.Println("rs verify:", outData)
    fmt.Println("------------------")

    //ES加签验签
    privateKey, _ = os.ReadFile("keys/es/private.pem")
    publicKey, _ = os.ReadFile("keys/es/public.pem")

    es := jwtex.ES{
        SignMethod: jwtex.ES512,
        PrivateKey: string(privateKey),
        PublicKey: string(publicKey),
    }
    sign, err = es.Sign(data)
    if err != nil {
        return
    }
    fmt.Println("es sign:", sign)

    outData = &jwtex.Data{}
    err = es.Verify(sign, outData)
    if err != nil {
        log.Println(err)
        return
    }
    fmt.Println("es verify:", outData)
    fmt.Println("------------------")


    //ED加签验签
    privateKey, _ = os.ReadFile("keys/ed/private.pem")
    publicKey, _ = os.ReadFile("keys/ed/public.pem")

    ed := jwtex.ED{
        PrivateKey: string(privateKey),
        PublicKey: string(publicKey),
    }
    sign, err = ed.Sign(data)
    if err != nil {
        return
    }
    fmt.Println("ed sign:", sign)

    outData = &jwtex.Data{}
    err = ed.Verify(sign, outData)
    if err != nil {
        log.Println(err)
        return
    }
    fmt.Println("ed verify:", outData)
    fmt.Println("------------------")
}
func GenerateKeys() {
    hs := secret.HsGenerator{
        Length: 256,
    }
    res, err := hs.Generate()
    fmt.Println(res, err)

    rs := secret.RsGenerator{}

    res, err = rs.Generate()
    fmt.Println(res, err)

    es := secret.ESGenerator{
        SignMethod: secret.ES512,
    }
    res, err = es.Generate()
    fmt.Println(res, err)

    ed := secret.EdGenerator{}
    res, err = ed.Generate()
    fmt.Println(res, err)
}

输出

hs sign: eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9.eyJOYW1lIjoieXVhbiIsIkFnZSI6MTEsIkdlbmRlciI6MiwiZXhwIjoxNjk3MDE4Nzk3LCJuYmYiOjE2OTcwMTUxOTcsImlhdCI6MTY5NzAxNTE5N30.dj2SMHiKmdvcyDRG6xvn_uYlQWsIzccE0AFgN863zwvJ4dWXZw4MgUTzoXh4DNVf
hs verify: &{yuan 11 2 {  [] 2023-10-11 18:06:37 +0800 CST 2023-10-11 17:06:37 +0800 CST 2023-10-11 17:06:37 +0800 CST }}
------------------
rs sign: eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyJOYW1lIjoieXVhbiIsIkFnZSI6MTEsIkdlbmRlciI6MiwiZXhwIjoxNjk3MDE4Nzk3LCJuYmYiOjE2OTcwMTUxOTcsImlhdCI6MTY5NzAxNTE5N30.j0ZBzRHQSAcDB7LlhuZMusqtwMNdYWXcz2tmI0W4Rs6VIBg3J3g04t5uag7MPjfWiNp85gcRKsjs3YVn5TKbFU29qTiLm3m8rsPW-rUI1b5W0aT5zJmHheNb0rmZ389vkaQHv1FlCoENKBIxjt62Vifg9YRqwbGWA1wFhgjGFJY
rs verify: &{yuan 11 2 {  [] 2023-10-11 18:06:37 +0800 CST 2023-10-11 17:06:37 +0800 CST 2023-10-11 17:06:37 +0800 CST }}
------------------
es sign: eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9.eyJOYW1lIjoieXVhbiIsIkFnZSI6MTEsIkdlbmRlciI6MiwiZXhwIjoxNjk3MDE4Nzk3LCJuYmYiOjE2OTcwMTUxOTcsImlhdCI6MTY5NzAxNTE5N30.AIjdHCKqIZUoxS7z9ETqi-1kh0l9AD9ZBz_pA9Vmo_ofGQB-TRTTCbIcOARAazKXz063b6m92oHiYbIXzYxUACu0APPNwcaCd7kyq6gFF4KxxxZQsT7NRB3OMWh5rHdtr-2gfKXQOjI5_pgD3odNfwFLOicKE7OPPoj0_6yB5LnDq7-P
es verify: &{yuan 11 2 {  [] 2023-10-11 18:06:37 +0800 CST 2023-10-11 17:06:37 +0800 CST 2023-10-11 17:06:37 +0800 CST }}
------------------
ed sign: eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJOYW1lIjoieXVhbiIsIkFnZSI6MTEsIkdlbmRlciI6MiwiZXhwIjoxNjk3MDE4Nzk3LCJuYmYiOjE2OTcwMTUxOTcsImlhdCI6MTY5NzAxNTE5N30.9b6z6sce5uCkIyI_JVYO_Ncjj7TG0jKvHQFoWdMFTqhGWPPd0mp2Tzy_4ILzubkxTB-GR9KLH0pIeUVanJxECw
ed verify: &{yuan 11 2 {  [] 2023-10-11 18:06:37 +0800 CST 2023-10-11 17:06:37 +0800 CST 2023-10-11 17:06:37 +0800 CST }}
------------------

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

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

相关文章

3D 人体研究

SynBody: Synthetic Dataset with Layered Human Models for 3D Human Perception and Modeling SynBody 是一个新的合成数据集,旨在推动 3D 人体研究的多样性和标注质量。它具有以下三个吸引人的特点: 服装参数化人体模型:可以生成各种不同…

智慧园区能源监控平台:构建绿色智能的未来城市

随着科技的发展的不断进步,在我国城镇化进程越来越快,园区做为产业集群的重要组成部分,其能源消耗和管理上的问题日益突显。为了应对这一考验,智慧园区能源监控平台应时而生,它利用大数据、云计算技术、物联网等尖端技…

云原生微服务治理 第四章 Spring Cloud Netflix 服务注册/发现组件Eureka

系列文章目录 第一章 Java线程池技术应用 第二章 CountDownLatch和Semaphone的应用 第三章 Spring Cloud 简介 第四章 Spring Cloud Netflix 之 Eureka 文章目录 系列文章目录[TOC](文章目录) 前言1、Eureka 两大组件2、Eureka 服务注册与发现3、案例3.1、创建主工程3.1.1、主…

栈的模拟实现(Java)

目录 1、 栈的概念2、栈的使用3、栈的模拟实现 1、 栈的概念 栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last I…

gpu cuda矩阵转置

欢迎关注更多精彩 关注我&#xff0c;学习常用算法与数据结构&#xff0c;一题多解&#xff0c;降维打击。 问题描述 给定1个二数组&#xff0c;利用gpu转置并返回结果。 cpu 算法 void cpu_matrix_trnspose(int in[N][M], int out[M][N]) {for (int y 0; y < N; y) {fo…

云原生安全应用场景有哪些?

当今数字化时代&#xff0c;数据已经成为企业最宝贵的资产之一&#xff0c;而云计算作为企业数字化转型的关键技术&#xff0c;其安全性也日益受到重视。随着云计算技术的快速发展&#xff0c;云原生安全应用场景也越来越广泛&#xff0c;下面本文将从云原生安全应用场景出发&a…

【Flutter学习】AppBar 和 PopupMenu

App Bar 可以视为页面的标题栏&#xff0c;在 Flutter 中用AppBar组件实现&#xff1b;Popup Menu 是弹出菜单&#xff0c;用PopupMenuButton实现。下面结合这两个组件说明其用法。 1. 代码实现 一个简单的AppBar实现代码如下&#xff1a; import package:flutter/material.…

ResNet分类器量化

1. 动态范围的常用计算方法 Max方法 之前的对称量化和非对称量化就是在用最大最小的办法做的 Histgram 直方图是一种用于可视化信号或数据分布的图形工具。计算动态范围的一种方法是通过查看直方图的范围。动态范围可以由直方图中的最高峰值和最低峰值之间的差异来估算。 E…

国内乳业龙头『君乐宝』×企企通强强联手,搭建采购供应链管理系统+商城平台双管齐下推动低碳转型

乳制品含有丰富且易吸收的营养物质&#xff0c;一直以来被认为是改善国民营养健康的重要产品&#xff0c;随着乳制品加工工艺的发展&#xff0c;市场上出现越来越多种类的乳制品供消费者选择。 随着中国经济发展、城镇化水平提高&#xff0c;以及年轻一代饮奶习惯的改变等因素&…

Table.Group系列_第4参数为全局的情况下,利用第5参数进行分组汇总

原始数据: 部门与职位存在于同一列中 实现功能: 根据筛选条件,可对部门或职位进行统计汇总第一列列名根据筛选自动变更,显示当前统计的维度 实现方式: 1. 构建筛选器内容 在任意空白单元格内输入需要筛选的内容 2. 插入"组合框"控件,并进行相应设置 从开发工具…

解决linux5.15编译时不生成boot.img 的问题

平台&#xff1a;rk3399 &#xff08;与平台关系不大&#xff09; 内核 &#xff1a;linux5.15 下一个linux5.15的内核&#xff0c;编译的时候 make ARCHarm64 CROSS_COMPILEaarch64-linux-gnu- -j6 rk3399-rock960.img 目标rk3399-rock960.img 需要在arch/arm64/boot/dts…

RK3588camera: AHD摄像头转MIPI转接芯片调试

我们常见的摄像头接口一般有MIPI、USB、DVP等等&#xff0c;但是MIPI摄像头受限于高速信号的传输距离问题&#xff0c;导致走线不能太长&#xff0c;这样在安防监控领域、车载等领域&#xff0c;使用就很受限&#xff0c;因此会引入一些技术延长摄像头的数据传输距离&#xff0…

Pytorch之SwinTransformer图像分类

文章目录 前言一、Swin Transformer1.Swin Transformer概览2.Patch Partition3.Patch Merging4.W-MSA5.SW-MSA(滑动窗口多头注意力机制)6.Relative Position bias(相对位置偏移)7.网络结构&#x1f947;Swin Transformer Block&#x1f948;Architecture 二、网络实现1.构建Eff…

【docker】Docker--harbor私有仓库部署与管理——重点

一、理论 1、本地私有仓库 只能在当前机器上做 #首先下载 registry 镜像 docker pull registry #在 daemon.json 文件中添加私有镜像仓库地址 vim /etc/docker/daemon.json { "insecure-registries": ["192.168.10.23:5000"], …

阿里云r8i内存型服务器ECS实例介绍_CPU性能_网络存储测评

阿里云服务器ECS内存型r8i实例CPU采用第四代Intel Xeon可扩展处理器&#xff08;Sapphire Rapids&#xff09;&#xff0c;基频2.7 GHz&#xff0c;全核睿频3.2 GHz&#xff0c;计算性能稳定&#xff0c;CPU内存比1:8&#xff0c;采用阿里云全新CIPU架构&#xff0c;CPU核心2核…

vue elementui的select组件实现滑到底部分页请求后端接口

vue elementui的select组件实现滑到底部分页请求后端接口 1.实现效果2.实现原理 1.实现效果 老规矩&#xff0c;直接上最后的实现效果 2.实现原理 直接上代码 <el-form-item class"diagmosisItem" label"诊断" v-scroll"handleScroll">…

Spring实战 | Spring IOC不能说的秘密?

国庆中秋特辑系列文章&#xff1a; 国庆中秋特辑&#xff08;八&#xff09;Spring Boot项目如何使用JPA 国庆中秋特辑&#xff08;七&#xff09;Java软件工程师常见20道编程面试题 国庆中秋特辑&#xff08;六&#xff09;大学生常见30道宝藏编程面试题 国庆中秋特辑&…

巧用h2-database.jar连接数据库

文章目录 一 、概述二、实践三、解决办法 一 、概述 H2 Database是一个开源的嵌入式数据库引擎&#xff0c;采用java语言编写&#xff0c;不受平台的限制&#xff0c;同时H2 Database提供了一个十分方便的web控制台用于操作和管理数据库内容。H2 Database还提供兼容模式&#…

hive数据表创建

目录 分隔符 分区表 二级分区 分桶表 外部表 分隔符 CREATE TABLE emp( userid bigint, emp_name array<string>, emp_date map<string,date>, other_info struct<deptname:string, gender:string>) ROW FORMAT DELIMITED FIELDS TERMINATED BY \t COL…

BN体系理解——类封装复现

from pathlib import Path from typing import Optionalimport torch import torch.nn as nn from torch import Tensorclass BN(nn.Module):def __init__(self,num_features,momentum0.1,eps1e-8):##num_features是通道数"""初始化方法:param num_features:特征…