github.com/binbinly/pkg@v0.0.11-0.20240321014439-f4fbf666eb0f/signature/signature.go (about) 1 package signature 2 3 import ( 4 "bytes" 5 "crypto/hmac" 6 "crypto/sha256" 7 "net/url" 8 "strconv" 9 "time" 10 11 "github.com/binbinly/pkg/util" 12 "github.com/binbinly/pkg/util/xhash" 13 ) 14 15 var _ Signature = (*signature)(nil) 16 17 // CryptoFunc 签名加密函数 18 type CryptoFunc func(b, k []byte) []byte 19 20 const ( 21 delimiter = "|" 22 ) 23 24 type Signature interface { 25 // Generate 生成签名 26 Generate(params any) (auth string, ts int64, err error) 27 // Verify 验证签名 28 Verify(auth string, ts int64, params any) (ok bool, err error) 29 } 30 31 type signature struct { 32 key string 33 secret string 34 ttl time.Duration 35 cryptoFunc CryptoFunc 36 } 37 38 func New(key, secret string, ttl time.Duration) Signature { 39 return &signature{ 40 key: key, 41 secret: secret, 42 ttl: ttl, 43 cryptoFunc: func(b, k []byte) []byte { 44 buf := bytes.NewBuffer(b) 45 buf.WriteString("&key=") 46 buf.Write(k) 47 return xhash.MD5(buf.Bytes()) 48 }, 49 } 50 } 51 52 func NewSha256(key, secret string, ttl time.Duration) Signature { 53 return &signature{ 54 key: key, 55 secret: secret, 56 ttl: ttl, 57 cryptoFunc: func(b, k []byte) []byte { 58 hash := hmac.New(sha256.New, k) 59 _, _ = hash.Write(b) 60 return hash.Sum(nil) 61 }, 62 } 63 } 64 65 func NewCrypto(key, secret string, ttl time.Duration, f CryptoFunc) Signature { 66 return &signature{ 67 key: key, 68 secret: secret, 69 ttl: ttl, 70 cryptoFunc: f, 71 } 72 } 73 74 func (s *signature) data(timestamp int64, params any) ([]byte, error) { 75 buffer := bytes.NewBufferString(strconv.FormatInt(timestamp, 10)) 76 buffer.WriteString(delimiter) 77 switch p := params.(type) { 78 case url.Values: 79 // Encode() 方法中自带 sorted by key 80 sortParamsEncode, err := url.QueryUnescape(p.Encode()) 81 if err != nil { 82 return nil, err 83 } 84 buffer.WriteString(sortParamsEncode) 85 case map[string]any: 86 buffer.WriteString(util.MapBuildQuery(p)) 87 case string: 88 buffer.WriteString(p) 89 } 90 91 return buffer.Bytes(), nil 92 }