feat: user check update reate

This commit is contained in:
zzw
2026-09-16 10:36:59 +08:00
parent 8457b46fe4
commit f94b610aa3
32 changed files with 1591 additions and 543 deletions
+18
View File
@@ -0,0 +1,18 @@
package config
import (
"lone-services/pkg/sms"
"lone-services/pkg/utils"
)
func NewSMS() (sms.SMS, error) {
return sms.New(sms.Config{
AccessKeyId: utils.GetConfigString("sms.accessKeyId"),
AccessKeySecret: utils.GetConfigString("sms.accessKeySecret"),
SignName: utils.GetConfigString("sms.signName"),
Endpoint: utils.GetConfigString("sms.endpoint"),
TemplateCode: utils.GetConfigString("sms.template.code"),
TemplatePwd: utils.GetConfigString("sms.template.password"),
Timeout: utils.GetConfigInt("sms.timeout"),
})
}
+9
View File
@@ -0,0 +1,9 @@
package dao
const (
SmsSceneLogin int32 = 1
SmsSceneResetPassword int32 = 2
SmsRateLimitSeconds = 60
SmsCodeLength = 6
)
@@ -22,3 +22,10 @@ func failResponse(status utils.Status) *chore.Response {
Msg: status.Msg,
}
}
func outResponse(status utils.Status, msg string) *chore.Response {
return &chore.Response{
Code: status.Code,
Msg: msg,
}
}
@@ -0,0 +1,120 @@
package logic
import (
"context"
"crypto/rand"
"fmt"
"math/big"
"strconv"
"time"
"lone-services/pkg/redis"
"lone-services/pkg/sms"
"lone-services/pkg/utils"
"lone-services/pkg/validate"
chore "lone-services/rpc/chore/pb"
"lone-services/services/chore/internal/dao"
"lone-services/services/chore/internal/svc"
"lone-services/services/chore/validator"
"github.com/zeromicro/go-zero/core/logx"
)
type SendSmsLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewSendSmsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *SendSmsLogic {
return &SendSmsLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
func (l *SendSmsLogic) SendSms(in *chore.SendSmsReq) (*chore.Response, error) {
var req validator.SendSmsValidator
if msg := validate.ValidateFromProto(in, &req); msg != utils.StringEmpty {
return outResponse(utils.ErrorParams, msg), nil
}
if l.svcCtx.SMS == nil {
return outResponse(utils.Fail, "短信服务未配置"), nil
}
kind, ok := smsSceneKind(req.Scene)
if !ok {
return outResponse(utils.ErrorParams, "短信场景不正确"), nil
}
freqKey := smsFreqRedisKey(req.Scene, req.Mobile)
okSet, err := redis.Client.SetNX(l.ctx, freqKey, "1", time.Duration(dao.SmsRateLimitSeconds)*time.Second).Result()
if err != nil {
l.Errorf("sms freq setnx: %v", err)
return failResponse(utils.Fail), nil
}
if !okSet {
return outResponse(utils.ErrorParams, "发送过于频繁,请稍后再试"), nil
}
code, err := genDigitCode(dao.SmsCodeLength)
if err != nil {
_ = redis.Client.Del(l.ctx, freqKey).Err()
l.Errorf("sms gen code: %v", err)
return failResponse(utils.Fail), nil
}
if err := l.svcCtx.SMS.SendByKind(req.Mobile, kind, map[string]string{"code": code}); err != nil {
_ = redis.Client.Del(l.ctx, freqKey).Err()
l.Errorf("sms send: %v", err)
return outResponse(utils.Fail, "短信发送失败"), nil
}
ttl := l.svcCtx.SMS.Timeout()
if ttl <= utils.NumberZero {
ttl = 600
}
codeKey := smsCodeRedisKey(req.Scene, req.Mobile)
if err := redis.Client.Set(l.ctx, codeKey, code, time.Duration(ttl)*time.Second).Err(); err != nil {
l.Errorf("sms cache code: %v", err)
return failResponse(utils.Fail), nil
}
return okResponse(nil), nil
}
func smsSceneKind(scene int32) (sms.TemplateKind, bool) {
switch scene {
case dao.SmsSceneLogin:
return sms.TemplateCode, true
case dao.SmsSceneResetPassword:
return sms.TemplatePassword, true
default:
return "", false
}
}
func smsCodeRedisKey(scene int32, mobile string) string {
return utils.CodeKey + strconv.Itoa(int(scene)) + ":" + mobile
}
func smsFreqRedisKey(scene int32, mobile string) string {
return "sms:freq:" + strconv.Itoa(int(scene)) + ":" + mobile
}
func genDigitCode(length int) (string, error) {
if length <= utils.NumberZero {
return utils.StringEmpty, fmt.Errorf("invalid code length")
}
out := make([]byte, length)
for i := range out {
n, err := rand.Int(rand.Reader, big.NewInt(10))
if err != nil {
return utils.StringEmpty, err
}
out[i] = byte('0' + n.Int64())
}
return string(out), nil
}
+26 -5
View File
@@ -2,11 +2,12 @@ package logic
import (
"context"
"fmt"
"lone-services/pkg/rpcclient"
"lone-services/pkg/utils"
chore "lone-services/rpc/chore/pb"
sale "lone-services/rpc/sale/pb"
user "lone-services/rpc/user/pb"
"lone-services/services/chore/internal/svc"
"github.com/zeromicro/go-zero/core/logx"
@@ -32,7 +33,8 @@ func NewTestLogic(ctx context.Context, svcCtx *svc.ServiceContext) *TestLogic {
func (l *TestLogic) Test(in *chore.TestReq) (*chore.Response, error) {
// cli, err := rpcclient.Get(l.svcCtx.ProductSvcName)
cli, err := rpcclient.Get(l.svcCtx.SaleSvcName)
// cli, err := rpcclient.Get(l.svcCtx.SaleSvcName)
cli, err := rpcclient.Get(l.svcCtx.UserSvcName)
if err != nil {
l.Errorf("get rpc: %v", err)
@@ -103,10 +105,29 @@ func (l *TestLogic) Test(in *chore.TestReq) (*chore.Response, error) {
// })
// ——————————————————————————————销售详情——————————————————————————————
res, err := sale.NewSaleClient(cli.Conn()).InfoInternal(l.ctx, &sale.InfoReq{
Id: int64(in.GetId()),
})
// res, err := sale.NewSaleClient(cli.Conn()).InfoInternal(l.ctx, &sale.InfoReq{
// Id: int64(in.GetId()),
// })
// ——————————————————————————————用户创建——————————————————————————————
// res, err := user.NewUserClient(cli.Conn()).InternalCheckCreate(l.ctx, &user.InternalCheckCreateReq{
// Mobile: in.GetChar(),
// })
// res, err := user.NewUserClient(cli.Conn()).InternalCheckUpdate(l.ctx, &user.InternalCheckUpdateReq{
// UserId: int64(in.GetId()),
// Mobile: in.GetChar(),
// })
// fmt.Println(res.GetResult())
res, err := user.NewUserClient(cli.Conn()).InternalCreate(l.ctx, &user.InternalCreateReq{
Mobile: in.GetChar(),
ClientCode: []string{"user_skin", "user_o2"},
CredentialType: []string{"password", "sms"},
Identifier: in.GetChar(),
Secret: "123123",
})
fmt.Println(res)
if err != nil {
l.Errorf("XXXXXX: %v", err)
return failResponse(utils.ErrorInternalServer), nil
@@ -1,5 +1,5 @@
// Code generated by goctl. DO NOT EDIT.
// goctl 1.10.2
// goctl 1.10.1
// Source: chore.proto
package server
@@ -43,6 +43,11 @@ func (s *ChoreServer) Regions(ctx context.Context, in *chore.RegionsReq) (*chore
return l.Regions(in)
}
func (s *ChoreServer) SendSms(ctx context.Context, in *chore.SendSmsReq) (*chore.Response, error) {
l := logic.NewSendSmsLogic(ctx, s.svcCtx)
return l.SendSms(in)
}
func (s *ChoreServer) AnswerItems(ctx context.Context, in *chore.EmptyReq) (*chore.Response, error) {
l := logic.NewAnswerItemsLogic(ctx, s.svcCtx)
return l.AnswerItems(in)
@@ -1,6 +1,7 @@
package svc
import (
"lone-services/pkg/sms"
"lone-services/pkg/utils"
"lone-services/services/chore/internal/config"
@@ -13,6 +14,8 @@ type ServiceContext struct {
DB *gorm.DB
ProductSvcName string
SaleSvcName string
UserSvcName string
SMS sms.SMS
}
func NewServiceContext(c config.Config, db *gorm.DB) *ServiceContext {
@@ -24,11 +27,22 @@ func NewServiceContext(c config.Config, db *gorm.DB) *ServiceContext {
if saleSvc == utils.StringEmpty {
logx.Error("config services.sale empty")
}
userSvc := utils.GetConfigString("services.user")
if userSvc == utils.StringEmpty {
logx.Error("config services.user empty")
}
smsClient, err := config.NewSMS()
if err != nil {
logx.Errorf("sms init: %v", err)
}
return &ServiceContext{
Config: c,
DB: db,
ProductSvcName: productSvc,
SaleSvcName: saleSvc,
UserSvcName: userSvc,
SMS: smsClient,
}
}