ibingli_digest.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. package signutil
  2. import (
  3. "crypto/sha1"
  4. "encoding/hex"
  5. "sort"
  6. "strconv"
  7. "strings"
  8. "time"
  9. validation "github.com/go-ozzo/ozzo-validation/v4"
  10. "gogs.baozhida.cn/Cold_Logistic_libs/pkg/contrib/errors"
  11. )
  12. const (
  13. AppidKey = "appid"
  14. NoncestrKey = "noncestr"
  15. TimestampKey = "timestamp"
  16. SignKey = "sign"
  17. )
  18. type GenSignFunc func(appid, secret, nonceStr, timestamp string) string
  19. type IBINGLIDigest struct {
  20. AppId string
  21. NonceStr string
  22. Timestamp string
  23. Sign string
  24. TimeLimit time.Duration
  25. genSignFunc GenSignFunc
  26. }
  27. type IBINGLIDigestOpt func(d *IBINGLIDigest)
  28. func WithIBINGLIDigestTimeLimit(t time.Duration) IBINGLIDigestOpt {
  29. return func(d *IBINGLIDigest) {
  30. d.TimeLimit = t
  31. }
  32. }
  33. func WithIBINGLIDigestGenSignFunc(f GenSignFunc) IBINGLIDigestOpt {
  34. return func(d *IBINGLIDigest) {
  35. d.genSignFunc = f
  36. }
  37. }
  38. func NewIBINGLIDigestByParam(param map[string]string, opts ...IBINGLIDigestOpt) *IBINGLIDigest {
  39. d := &IBINGLIDigest{
  40. AppId: param[AppidKey],
  41. NonceStr: param[NoncestrKey],
  42. Timestamp: param[TimestampKey],
  43. Sign: param[SignKey],
  44. genSignFunc: defaultGenSign,
  45. }
  46. for _, opt := range opts {
  47. opt(d)
  48. }
  49. return d
  50. }
  51. func NewIBINGLIDigest(appId, nonceStr, timestamp, sign string, opts ...IBINGLIDigestOpt) *IBINGLIDigest {
  52. d := &IBINGLIDigest{
  53. AppId: appId,
  54. NonceStr: nonceStr,
  55. Timestamp: timestamp,
  56. Sign: sign,
  57. genSignFunc: defaultGenSign,
  58. }
  59. for _, opt := range opts {
  60. opt(d)
  61. }
  62. return d
  63. }
  64. func (v *IBINGLIDigest) Validate() error {
  65. err := validation.ValidateStruct(v,
  66. validation.Field(&v.AppId, validation.Required),
  67. validation.Field(&v.NonceStr, validation.Required),
  68. validation.Field(&v.Timestamp, validation.Required),
  69. validation.Field(&v.Sign, validation.Required),
  70. )
  71. if err != nil {
  72. return err
  73. }
  74. if v.TimeLimit > 0 {
  75. return v.ValidateTimestamp()
  76. }
  77. return nil
  78. }
  79. // 验证时效性
  80. func (v *IBINGLIDigest) ValidateTimestamp() error {
  81. ts, err := strconv.Atoi(v.Timestamp)
  82. if err != nil {
  83. return errors.WithStackOnce(err)
  84. }
  85. if time.Now().Sub(time.UnixMilli(int64(ts))) > v.TimeLimit {
  86. return errors.New("timestamp invalid")
  87. }
  88. return nil
  89. }
  90. func defaultGenSign(appid, secret, nonceStr, timestamp string) string {
  91. // /*
  92. // 签名规则:
  93. // 1. 拼接appid和secret字符串
  94. // 2. 随机生成一个16位字符串,由[0~9a~zA~Z]组成
  95. // 3. 使用当前13位时间戳(毫秒值)
  96. // 4. 拼接123中的字符串
  97. // 5. 字典排序4中的字符串
  98. // 6. 计算字符串的SHA1校验和
  99. // */
  100. target := appid + secret + nonceStr + timestamp
  101. targetStrArray := strings.Split(target, "")
  102. sort.Strings(targetStrArray)
  103. target = strings.Join(targetStrArray, "")
  104. h := sha1.New()
  105. h.Write([]byte(target))
  106. sum := h.Sum(nil)
  107. return hex.EncodeToString(sum)
  108. }
  109. // 生成签名
  110. func (v *IBINGLIDigest) GenSign(secret string) string {
  111. return v.genSignFunc(v.AppId, secret, v.NonceStr, v.Timestamp)
  112. }
  113. // 比较签名
  114. func (v *IBINGLIDigest) CompareSign(secret string) bool {
  115. return v.Sign == v.GenSign(secret)
  116. }