b_verify_code.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. package internal
  2. import (
  3. "context"
  4. "encoding/json"
  5. "fmt"
  6. "github.com/gogf/gf/v2/encoding/gjson"
  7. "github.com/gogf/gf/v2/os/glog"
  8. rand "math/rand"
  9. "strings"
  10. "sync"
  11. "time"
  12. "yx-dataset-server/app/errors"
  13. "yx-dataset-server/app/model"
  14. "yx-dataset-server/app/schema"
  15. "yx-dataset-server/library/logger"
  16. "yx-dataset-server/library/redis"
  17. "yx-dataset-server/library/sms"
  18. "yx-dataset-server/library/utils"
  19. )
  20. // NewVerifyCode 创建VerifyCode
  21. func NewVerifyCode(
  22. mUser model.IUser,
  23. ) *VerifyCode {
  24. return &VerifyCode{
  25. userModel: mUser,
  26. }
  27. }
  28. // VerifyCode 创建VerifyCode对象
  29. type VerifyCode struct {
  30. sync.RWMutex
  31. userModel model.IUser
  32. }
  33. func (a *VerifyCode) getKey(businessType int, tel, storeType string) string {
  34. return utils.Base64Encode(fmt.Sprintf("%d%s%s", businessType, tel, storeType))
  35. }
  36. // Check 检查手机号及验证码的有效性
  37. func (a *VerifyCode) Check(ctx context.Context, req schema.VerifyCodeCheck) (bool, error) {
  38. if req.Tel == "" || len(req.Tel) < 11 {
  39. return false, errors.New("请输入合法的手机号")
  40. }
  41. var businessType string
  42. switch req.BusinessType {
  43. case 1:
  44. businessType = "login"
  45. case 2:
  46. businessType = "changePass"
  47. default:
  48. return false, errors.New("业务类型参数不正确")
  49. }
  50. if req.Token == "" {
  51. req.Token = fmt.Sprintf("%s:%s:%s", businessType, "code", req.Tel)
  52. }
  53. val, err := redis.GetClient().Get(ctx, req.Token)
  54. if err != nil {
  55. return false, errors.ErrBadRequest
  56. } else if val == "" {
  57. return false, errors.New("验证码已失效,请重新获取验证码")
  58. }
  59. var item schema.VerifyCodeItem
  60. if err := json.Unmarshal([]byte(val), &item); err != nil {
  61. return false, err
  62. }
  63. return item.Code == req.Code && item.BusinessType == req.BusinessType, nil
  64. }
  65. // SendCode 发送短信验证码
  66. func (a *VerifyCode) ALiYunSendSms(ctx context.Context, req schema.VerifyCodeRequest) (*schema.VerifyCodeResponse, error) {
  67. a.Lock()
  68. defer a.Unlock()
  69. switch req.Bzty {
  70. case 1:
  71. req.TemplateId = utils.GetConfig("aliyun_sms.loginTemplateCode").String()
  72. req.BusinessTypeStr = "login"
  73. case 2:
  74. req.TemplateId = utils.GetConfig("aliyun_sms.passwordTemplateCode").String()
  75. req.BusinessTypeStr = "changePass"
  76. }
  77. telStoreKey := fmt.Sprintf("%s:%s", "telCount", req.Tel)
  78. telStoreData, err := redis.GetClient().Get(ctx, telStoreKey)
  79. if err != nil {
  80. return nil, errors.ErrBadRequest
  81. }
  82. if telStoreData != "" {
  83. var telStoreItem schema.StoreCountItem
  84. _ = json.NewDecoder(strings.NewReader(telStoreData)).Decode(&telStoreItem)
  85. if telStoreItem.Count >= 50 {
  86. return nil, errors.New("该手机号已被限制获取验证码,请于次日重试")
  87. }
  88. req.TelCount = telStoreItem.Count
  89. }
  90. codeKey := fmt.Sprintf("%s:%s:%s", req.BusinessTypeStr, "code", req.Tel)
  91. err = a.aliyunSend(ctx, req)
  92. if err != nil {
  93. return nil, err
  94. }
  95. logger.Printf(ctx, "短信发送成功:[手机号:%s]", req.Tel[7:11])
  96. return &schema.VerifyCodeResponse{
  97. Token: codeKey,
  98. }, nil
  99. }
  100. func (a *VerifyCode) aliyunSend(ctx context.Context, req schema.VerifyCodeRequest) error {
  101. if req.Batch {
  102. return sms.SendBatchSms(sms.ALiYunSendBatchSmsArgs{
  103. TemplateCode: req.TemplateId,
  104. TemplateParam: req.ParamsJson,
  105. PhoneNumbers: req.Tel,
  106. })
  107. }
  108. // 随机生成6位验证码
  109. code := fmt.Sprintf("%06v", rand.New(rand.NewSource(time.Now().UnixNano())).Int31n(1000000))
  110. paramJson := gjson.New("")
  111. _ = paramJson.Set("code", code)
  112. glog.Infof(ctx, "验证码发送成功[手机号%s,验证码:%s]", req.Tel, code)
  113. //发送短信验证码
  114. err := sms.SendSms(sms.ALiYunSendSmsArgs{
  115. TemplateCode: req.TemplateId,
  116. TemplateParam: paramJson.MustToJsonString(),
  117. PhoneNumbers: req.Tel,
  118. })
  119. if err != nil {
  120. return err
  121. }
  122. expired := time.Minute * 5
  123. resendLimit := time.Second * 60
  124. // 存储重发限制
  125. resendLimitKey := fmt.Sprintf("%s:%s:%s", req.BusinessTypeStr, "checkResend", req.Tel)
  126. err = redis.GetClient().Set(ctx, resendLimitKey, 1, resendLimit)
  127. if err != nil {
  128. return errors.ErrBadRequest
  129. }
  130. // 存储验证码
  131. codeKey := fmt.Sprintf("%s:%s:%s", req.BusinessTypeStr, "code", req.Tel)
  132. codeData := schema.VerifyCodeItem{
  133. Code: code,
  134. BusinessType: req.Bzty,
  135. }
  136. err = redis.GetClient().Set(ctx, codeKey, codeData, expired)
  137. if err != nil {
  138. return errors.ErrBadRequest
  139. }
  140. return nil
  141. }