最新消息: USBMI致力于为网友们分享Windows、安卓、IOS等主流手机系统相关的资讯以及评测、同时提供相关教程、应用、软件下载等服务。

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

互联网 admin 4浏览 0评论

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

golang JWT加签算法及使用案例

JWT原理

查看官方lib库
官方lib库

选择go语言

数据结构定义

secret.go

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

x509封装

x509PemGen.go

package secretimport ("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 := priNamepublicKeyFileName := pubNameprivateFile, 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 secretimport ("encoding/hex""math/rand""time"
)// HS的密钥可以是一个随机的字符串
type HsGenerator struct {Length int}func (hs *HsGenerator) Generate() (*OutSecret, error) {out := OutSecret{}length := 32if 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 secretimport ("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 = privateKeyFileNameout.PublicKeyFile = publicKeyFileNamereturn &out, err
}
ES签名密钥生成

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

案例

package secretimport ("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 = privateKeyFileNameout.PublicKeyFile = publicKeyFileNamereturn &out, err
}
ED签名密钥生成

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

案例

package secretimport ("crypto/ed25519""crypto/rand""crypto/x509""log""os"
)// 扭曲爱德华曲线//RSA,生成公钥私钥文件,可以通过openSSL生成也可以type EdGenerator struct {}func (ed *EdGenerator) Generate() (*OutSecret, error) {out := OutSecret{}var err errorpublicKey, 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 = privateKeyFileNameout.PublicKeyFile = publicKeyFileNamereturn &out, err
}
HS、RS、ES、ED加签与验签

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

测试数据结构定义

package jwteximport ("github/golang-jwt/jwt/v4"
)type Data struct {// 自定义字段Name   stringAge    intGender 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 jwteximport ("github/golang-jwt/jwt/v4""log"
)type HS struct {Key stringSignMethod HSSignMethod
}type HSSignMethod stringconst (HS256 HSSignMethod = "HS256"HS384 HSSignMethod = "HS384"HS512 HSSignMethod = "HS512"
)
func (hs *HS)getMethod() *jwt.SigningMethodHMAC{switch hs.SignMethod {case HS256:return jwt.SigningMethodHS256case HS384:return jwt.SigningMethodHS384case 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 jwteximport ("github/golang-jwt/jwt/v4""log"
)type RS struct {SignMethod RSSignMethod// 密钥对PrivateKey stringPublicKey string
}type RSSignMethod stringconst (RS256 RSSignMethod = "RS256"RS384 RSSignMethod = "RS384"RS512 RSSignMethod = "RS512"
)func (rs *RS)getMethod() *jwt.SigningMethodRSA{switch rs.SignMethod {case RS256:return jwt.SigningMethodRS256case RS384:return jwt.SigningMethodRS384case 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 jwteximport ("github/golang-jwt/jwt/v4""log"
)type ES struct {SignMethod ESSignMethod// 密钥对PrivateKey stringPublicKey string
}type ESSignMethod stringconst (ES256 ESSignMethod = "ES256"ES384 ESSignMethod = "ES384"ES512 ESSignMethod = "ES512"
)func (es *ES)getMethod() *jwt.SigningMethodECDSA{switch es.SignMethod {case ES256:return jwt.SigningMethodES256case ES384:return jwt.SigningMethodES384case 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 jwteximport ("github/golang-jwt/jwt/v4""log"
)type ED struct {// 密钥对PrivateKey stringPublicKey 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 mainimport ("fmt""github/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 }}
------------------

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

golang JWT加签算法及使用案例

JWT原理

查看官方lib库
官方lib库

选择go语言

数据结构定义

secret.go

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

x509封装

x509PemGen.go

package secretimport ("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 := priNamepublicKeyFileName := pubNameprivateFile, 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 secretimport ("encoding/hex""math/rand""time"
)// HS的密钥可以是一个随机的字符串
type HsGenerator struct {Length int}func (hs *HsGenerator) Generate() (*OutSecret, error) {out := OutSecret{}length := 32if 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 secretimport ("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 = privateKeyFileNameout.PublicKeyFile = publicKeyFileNamereturn &out, err
}
ES签名密钥生成

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

案例

package secretimport ("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 = privateKeyFileNameout.PublicKeyFile = publicKeyFileNamereturn &out, err
}
ED签名密钥生成

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

案例

package secretimport ("crypto/ed25519""crypto/rand""crypto/x509""log""os"
)// 扭曲爱德华曲线//RSA,生成公钥私钥文件,可以通过openSSL生成也可以type EdGenerator struct {}func (ed *EdGenerator) Generate() (*OutSecret, error) {out := OutSecret{}var err errorpublicKey, 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 = privateKeyFileNameout.PublicKeyFile = publicKeyFileNamereturn &out, err
}
HS、RS、ES、ED加签与验签

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

测试数据结构定义

package jwteximport ("github/golang-jwt/jwt/v4"
)type Data struct {// 自定义字段Name   stringAge    intGender 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 jwteximport ("github/golang-jwt/jwt/v4""log"
)type HS struct {Key stringSignMethod HSSignMethod
}type HSSignMethod stringconst (HS256 HSSignMethod = "HS256"HS384 HSSignMethod = "HS384"HS512 HSSignMethod = "HS512"
)
func (hs *HS)getMethod() *jwt.SigningMethodHMAC{switch hs.SignMethod {case HS256:return jwt.SigningMethodHS256case HS384:return jwt.SigningMethodHS384case 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 jwteximport ("github/golang-jwt/jwt/v4""log"
)type RS struct {SignMethod RSSignMethod// 密钥对PrivateKey stringPublicKey string
}type RSSignMethod stringconst (RS256 RSSignMethod = "RS256"RS384 RSSignMethod = "RS384"RS512 RSSignMethod = "RS512"
)func (rs *RS)getMethod() *jwt.SigningMethodRSA{switch rs.SignMethod {case RS256:return jwt.SigningMethodRS256case RS384:return jwt.SigningMethodRS384case 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 jwteximport ("github/golang-jwt/jwt/v4""log"
)type ES struct {SignMethod ESSignMethod// 密钥对PrivateKey stringPublicKey string
}type ESSignMethod stringconst (ES256 ESSignMethod = "ES256"ES384 ESSignMethod = "ES384"ES512 ESSignMethod = "ES512"
)func (es *ES)getMethod() *jwt.SigningMethodECDSA{switch es.SignMethod {case ES256:return jwt.SigningMethodES256case ES384:return jwt.SigningMethodES384case 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 jwteximport ("github/golang-jwt/jwt/v4""log"
)type ED struct {// 密钥对PrivateKey stringPublicKey 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 mainimport ("fmt""github/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 }}
------------------
发布评论

评论列表 (0)

  1. 暂无评论