123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135 |
- package signutil
- import (
- "crypto/sha1"
- "encoding/hex"
- "sort"
- "strconv"
- "strings"
- "time"
- validation "github.com/go-ozzo/ozzo-validation/v4"
- "gogs.baozhida.cn/Cold_Logistic_libs/pkg/contrib/errors"
- )
- const (
- AppidKey = "appid"
- NoncestrKey = "noncestr"
- TimestampKey = "timestamp"
- SignKey = "sign"
- )
- type GenSignFunc func(appid, secret, nonceStr, timestamp string) string
- type IBINGLIDigest struct {
- AppId string
- NonceStr string
- Timestamp string
- Sign string
- TimeLimit time.Duration
- genSignFunc GenSignFunc
- }
- type IBINGLIDigestOpt func(d *IBINGLIDigest)
- func WithIBINGLIDigestTimeLimit(t time.Duration) IBINGLIDigestOpt {
- return func(d *IBINGLIDigest) {
- d.TimeLimit = t
- }
- }
- func WithIBINGLIDigestGenSignFunc(f GenSignFunc) IBINGLIDigestOpt {
- return func(d *IBINGLIDigest) {
- d.genSignFunc = f
- }
- }
- func NewIBINGLIDigestByParam(param map[string]string, opts ...IBINGLIDigestOpt) *IBINGLIDigest {
- d := &IBINGLIDigest{
- AppId: param[AppidKey],
- NonceStr: param[NoncestrKey],
- Timestamp: param[TimestampKey],
- Sign: param[SignKey],
- genSignFunc: defaultGenSign,
- }
- for _, opt := range opts {
- opt(d)
- }
- return d
- }
- func NewIBINGLIDigest(appId, nonceStr, timestamp, sign string, opts ...IBINGLIDigestOpt) *IBINGLIDigest {
- d := &IBINGLIDigest{
- AppId: appId,
- NonceStr: nonceStr,
- Timestamp: timestamp,
- Sign: sign,
- genSignFunc: defaultGenSign,
- }
- for _, opt := range opts {
- opt(d)
- }
- return d
- }
- func (v *IBINGLIDigest) Validate() error {
- err := validation.ValidateStruct(v,
- validation.Field(&v.AppId, validation.Required),
- validation.Field(&v.NonceStr, validation.Required),
- validation.Field(&v.Timestamp, validation.Required),
- validation.Field(&v.Sign, validation.Required),
- )
- if err != nil {
- return err
- }
- if v.TimeLimit > 0 {
- return v.ValidateTimestamp()
- }
- return nil
- }
- // 验证时效性
- func (v *IBINGLIDigest) ValidateTimestamp() error {
- ts, err := strconv.Atoi(v.Timestamp)
- if err != nil {
- return errors.WithStackOnce(err)
- }
- if time.Now().Sub(time.UnixMilli(int64(ts))) > v.TimeLimit {
- return errors.New("timestamp invalid")
- }
- return nil
- }
- func defaultGenSign(appid, secret, nonceStr, timestamp string) string {
- // /*
- // 签名规则:
- // 1. 拼接appid和secret字符串
- // 2. 随机生成一个16位字符串,由[0~9a~zA~Z]组成
- // 3. 使用当前13位时间戳(毫秒值)
- // 4. 拼接123中的字符串
- // 5. 字典排序4中的字符串
- // 6. 计算字符串的SHA1校验和
- // */
- target := appid + secret + nonceStr + timestamp
- targetStrArray := strings.Split(target, "")
- sort.Strings(targetStrArray)
- target = strings.Join(targetStrArray, "")
- h := sha1.New()
- h.Write([]byte(target))
- sum := h.Sum(nil)
- return hex.EncodeToString(sum)
- }
- // 生成签名
- func (v *IBINGLIDigest) GenSign(secret string) string {
- return v.genSignFunc(v.AppId, secret, v.NonceStr, v.Timestamp)
- }
- // 比较签名
- func (v *IBINGLIDigest) CompareSign(secret string) bool {
- return v.Sign == v.GenSign(secret)
- }
|