From e1f6d3c822e764a35cfcd3a345837f29205fe9a4 Mon Sep 17 00:00:00 2001 From: Eigeen Date: Sun, 3 Apr 2022 13:29:47 +0800 Subject: [PATCH] =?UTF-8?q?:sparkles:Feat:=20jwt=20token=E5=8A=A0=E5=AF=86?= =?UTF-8?q?=E7=AE=97=E6=B3=95=E7=94=B1ES256=E6=9B=B4=E6=8D=A2=E4=B8=BAHS25?= =?UTF-8?q?6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/config.full.yml | 9 ++--- config/config.go | 9 ++++- config/config_test.go | 2 +- config/defaults.go | 5 +++ pkg/common/token.go | 75 +++-------------------------------- pkg/common/token_test.go | 4 -- pkg/utils/key.go | 86 +++++----------------------------------- pkg/utils/key_test.go | 32 --------------- 8 files changed, 34 insertions(+), 188 deletions(-) create mode 100644 config/defaults.go delete mode 100644 pkg/utils/key_test.go diff --git a/config/config.full.yml b/config/config.full.yml index c04833d..2161207 100644 --- a/config/config.full.yml +++ b/config/config.full.yml @@ -1,4 +1,4 @@ -# 应用版本,应与当前版本一致 +# 应用版本 version: {{ .Version }} # 应用配置 @@ -15,9 +15,8 @@ security: expire: 14400 # Refresh Token过期时间 (默认24小时) refresh-expire: 86400 - # 以下字段指定key的文件路径 - private-key: id_ecdsa - public-key: id_ecdsa.pub + # 请确保签名密钥安全性足够高,建议使用高强度随机字符串 + secret: {{ .Security.Jwt.Secret }} # 允许额外的跨域请求 allow-CORS: - "*" @@ -31,7 +30,7 @@ database: # mysql https://github.com/go-sql-driver/mysql#dsn-data-source-name # postgres https://github.com/lib/pq + # with unit second max-idle-conns: 20 max-open-conns: 50 - # with unit sec conn-max-life-time: 30 diff --git a/config/config.go b/config/config.go index 5e4776f..534f8eb 100644 --- a/config/config.go +++ b/config/config.go @@ -22,8 +22,7 @@ type Config struct { Jwt struct { Expire uint32 RefreshExpire uint32 `yaml:"refresh-expire"` - PrivateKey string `yaml:"private-key"` - PublicKey string `yaml:"public-key"` + Secret string } } Database struct { @@ -39,6 +38,9 @@ var configFull string // 加载配置文件 func SetupConfig() { + // 加载默认配置 + Cfg = DefCfg + // 读取配置文件,若不存在则创建 if isExist := utils.FileExist("config.yml"); !isExist { newCfgFile() @@ -82,6 +84,9 @@ func parseConfigTmpl() []byte { // 创建配置文件 func newCfgFile() { + // 生成Key + Cfg.Security.Jwt.Secret = utils.NewKey() + // 解析配置文件模板 tmplBytes := parseConfigTmpl() diff --git a/config/config_test.go b/config/config_test.go index a8aab58..25be9f1 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -3,5 +3,5 @@ package config import "testing" func TestSetupConfig(t *testing.T) { - Cfg.Version = "0.0.1-dev" + SetupConfig() } diff --git a/config/defaults.go b/config/defaults.go new file mode 100644 index 0000000..b7766d5 --- /dev/null +++ b/config/defaults.go @@ -0,0 +1,5 @@ +package config + +var DefCfg = Config{ + Version: "0.0.1-dev", +} diff --git a/pkg/common/token.go b/pkg/common/token.go index 9c746e3..f40f3e7 100644 --- a/pkg/common/token.go +++ b/pkg/common/token.go @@ -1,15 +1,8 @@ package common import ( - "crypto/ecdsa" - "crypto/elliptic" - "crypto/rand" "drive-linked/config" - "drive-linked/pkg/utils" "github.com/golang-jwt/jwt/v4" - "github.com/kataras/golog" - "io/ioutil" - "os" "time" ) @@ -18,71 +11,15 @@ type JwtClaims struct { jwt.RegisteredClaims } -var ECDSAKey *ecdsa.PrivateKey - -// 生成ES256密钥对,并保存在文件中 -func init() { - // 密钥对存在时跳过 - //TODO:bug:会重复生成key - if isExist := utils.FileExist("id_ecdsa") && utils.FileExist("id_ecdsa.pub"); isExist { - return - } - - key, err := newES256Key() - if err != nil { - golog.Fatal("生成ES256密钥错误") - } - - // 写入至文件 - pubKeyBytes, err := utils.EncodePublicKey(&key.PublicKey) - if err != nil { - golog.Fatal(err) - } - priKeyBytes, err := utils.EncodePrivateKey(key) - if err != nil { - golog.Fatal(err) - } - - priKeyFile, err := os.OpenFile("id_ecdsa", os.O_CREATE, 0600) - if err != nil { - golog.Fatal(err) - } - pubKeyFile, err := os.OpenFile("id_ecdsa.pub", os.O_CREATE, 0655) - if err != nil { - golog.Fatal(err) - } - priKeyFile.Write(priKeyBytes) - pubKeyFile.Write(pubKeyBytes) -} - -func newES256Key() (key *ecdsa.PrivateKey, err error) { - key, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - return key, err -} - -func LoadKey() error { - if ECDSAKey != nil { - return nil - } - - priKeyBytes, err := ioutil.ReadFile(config.Cfg.Security.Jwt.PrivateKey) - if err != nil { - return err - } - key, err := utils.DecodePrivateKey(priKeyBytes) - if err != nil { - return err - } - ECDSAKey = key - return nil -} - //TODO:token解密验证 func ValidateLogin(token string) error { return nil } func NewToken(auds ...string) (string, error) { + if len(auds) == 0 { + auds = []string{"nonAudience"} + } // Create the claims claims := JwtClaims{ "bar", @@ -93,12 +30,12 @@ func NewToken(auds ...string) (string, error) { NotBefore: jwt.NewNumericDate(time.Now()), Issuer: "drivelinked", Subject: "login", - Audience: []string{"eigeen"}, + Audience: auds, }, } - token := jwt.NewWithClaims(jwt.SigningMethodES256, claims) - ss, err := token.SignedString(ECDSAKey) + token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + ss, err := token.SignedString([]byte(config.Cfg.Security.Jwt.Secret)) if err != nil { return "", err } diff --git a/pkg/common/token_test.go b/pkg/common/token_test.go index 6e0bb75..c83e630 100644 --- a/pkg/common/token_test.go +++ b/pkg/common/token_test.go @@ -7,10 +7,6 @@ import ( func TestNewToken(t *testing.T) { config.SetupConfig() - err := LoadKey() - if err != nil { - t.Fatal(err) - } token, err := NewToken("eigeen") if err != nil { diff --git a/pkg/utils/key.go b/pkg/utils/key.go index 309cbe9..ceaaf47 100644 --- a/pkg/utils/key.go +++ b/pkg/utils/key.go @@ -1,84 +1,20 @@ package utils import ( - "crypto/ecdsa" - "crypto/x509" - "encoding/pem" - "errors" - "fmt" + "crypto/rand" + "encoding/hex" + "github.com/kataras/golog" ) -func DecodePublicKey(encodedKey []byte) (*ecdsa.PublicKey, error) { - block, _ := pem.Decode(encodedKey) - if block == nil || block.Type != "PUBLIC KEY" { - return nil, fmt.Errorf("marshal: could not decode PEM block type %s", block.Type) - - } - - pub, err := x509.ParsePKIXPublicKey(block.Bytes) +// NewKey 生成Key +func NewKey() string { + length := 48 + // HS256的key,其实就是个随机字符串生成器 + key := make([]byte, length/2) + _, err := rand.Read(key) if err != nil { - return nil, err + golog.Fatal(err) } - ecdsaPub, ok := pub.(*ecdsa.PublicKey) - if !ok { - return nil, errors.New("marshal: data was not an ECDSA public key") - } - - return ecdsaPub, nil -} - -func EncodePublicKey(key *ecdsa.PublicKey) ([]byte, error) { - derBytes, err := x509.MarshalPKIXPublicKey(key) - if err != nil { - return nil, err - } - - block := &pem.Block{ - Type: "PUBLIC KEY", - Bytes: derBytes, - } - - return pem.EncodeToMemory(block), nil -} - -func DecodePrivateKey(encodedKey []byte) (*ecdsa.PrivateKey, error) { - var skippedTypes []string - var block *pem.Block - - for { - block, encodedKey = pem.Decode(encodedKey) - - if block == nil { - return nil, fmt.Errorf("failed to find EC PRIVATE KEY in PEM data after skipping types %v", skippedTypes) - } - - if block.Type == "EC PRIVATE KEY" { - break - } else { - skippedTypes = append(skippedTypes, block.Type) - continue - } - } - - privKey, err := x509.ParseECPrivateKey(block.Bytes) - if err != nil { - return nil, err - } - - return privKey, nil -} - -func EncodePrivateKey(key *ecdsa.PrivateKey) ([]byte, error) { - derKey, err := x509.MarshalECPrivateKey(key) - if err != nil { - return nil, err - } - - keyBlock := &pem.Block{ - Type: "EC PRIVATE KEY", - Bytes: derKey, - } - - return pem.EncodeToMemory(keyBlock), nil + return hex.EncodeToString(key) } diff --git a/pkg/utils/key_test.go b/pkg/utils/key_test.go deleted file mode 100644 index 157a52d..0000000 --- a/pkg/utils/key_test.go +++ /dev/null @@ -1,32 +0,0 @@ -package utils - -import ( - "io/ioutil" - "testing" -) - -func TestDecodePrivateKey(t *testing.T) { - priKeyStr, err := ioutil.ReadFile("../../config/id_ecdsa") - if err != nil { - t.Fatal(err) - } - - key, err := DecodePrivateKey(priKeyStr) - if err != nil { - t.Error(err) - } - t.Log(key) -} - -func TestDecodePublicKey(t *testing.T) { - priKeyStr, err := ioutil.ReadFile("../../config/id_ecdsa.pub") - if err != nil { - t.Fatal(err) - } - - key, err := DecodePublicKey(priKeyStr) - if err != nil { - t.Error(err) - } - t.Log(key) -}