package sign import ( "crypto/hmac" "crypto/sha256" "encoding/base64" "io" "strconv" "strings" "time" ) type HMACSign struct { SecretKey []byte } func (s HMACSign) Sign(data string, expire int64) string { h := hmac.New(sha256.New, s.SecretKey) expireTimeStamp := strconv.FormatInt(expire, 10) _, err := io.WriteString(h, data+":"+expireTimeStamp) if err != nil { return "" } return base64.URLEncoding.EncodeToString(h.Sum(nil)) + ":" + expireTimeStamp } func (s HMACSign) Verify(data, sign string) error { signSlice := strings.Split(sign, ":") // check whether contains expire time if signSlice[len(signSlice)-1] == "" { return ErrExpireMissing } // check whether expire time is expired expires, err := strconv.ParseInt(signSlice[len(signSlice)-1], 10, 64) if err != nil { return ErrExpireInvalid } // if expire time is expired, return error if expires < time.Now().Unix() && expires != 0 { return ErrSignExpired } // verify sign if s.Sign(data, expires) != sign { return ErrSignInvalid } return nil } func NewHMACSign(secret []byte) Sign { return HMACSign{SecretKey: secret} }