package sms import ( "context" "crypto/rand" "fmt" "math/big" "github.com/aliyun/alibaba-cloud-sdk-go/services/dysmsapi" "go.uber.org/zap" "tyapi-server/internal/config" ) // AliSMSService 阿里云短信服务 type AliSMSService struct { client *dysmsapi.Client config config.SMSConfig logger *zap.Logger } // NewAliSMSService 创建阿里云短信服务 func NewAliSMSService(cfg config.SMSConfig, logger *zap.Logger) (*AliSMSService, error) { client, err := dysmsapi.NewClientWithAccessKey("cn-hangzhou", cfg.AccessKeyID, cfg.AccessKeySecret) if err != nil { return nil, fmt.Errorf("创建短信客户端失败: %w", err) } return &AliSMSService{ client: client, config: cfg, logger: logger, }, nil } // SendVerificationCode 发送验证码 func (s *AliSMSService) SendVerificationCode(ctx context.Context, phone string, code string) error { request := dysmsapi.CreateSendSmsRequest() request.Scheme = "https" request.PhoneNumbers = phone request.SignName = s.config.SignName request.TemplateCode = s.config.TemplateCode request.TemplateParam = fmt.Sprintf(`{"code":"%s"}`, code) response, err := s.client.SendSms(request) if err != nil { s.logger.Error("Failed to send SMS", zap.String("phone", phone), zap.Error(err)) return fmt.Errorf("短信发送失败: %w", err) } if response.Code != "OK" { s.logger.Error("SMS send failed", zap.String("phone", phone), zap.String("code", response.Code), zap.String("message", response.Message)) return fmt.Errorf("短信发送失败: %s - %s", response.Code, response.Message) } s.logger.Info("SMS sent successfully", zap.String("phone", phone), zap.String("bizId", response.BizId)) return nil } // GenerateCode 生成验证码 func (s *AliSMSService) GenerateCode(length int) string { if length <= 0 { length = 6 } // 生成指定长度的数字验证码 max := big.NewInt(int64(pow10(length))) n, _ := rand.Int(rand.Reader, max) // 格式化为指定长度,不足时前面补0 format := fmt.Sprintf("%%0%dd", length) return fmt.Sprintf(format, n.Int64()) } // pow10 计算10的n次方 func pow10(n int) int { result := 1 for i := 0; i < n; i++ { result *= 10 } return result } // MockSMSService 模拟短信服务(用于开发和测试) type MockSMSService struct { logger *zap.Logger } // NewMockSMSService 创建模拟短信服务 func NewMockSMSService(logger *zap.Logger) *MockSMSService { return &MockSMSService{ logger: logger, } } // SendVerificationCode 模拟发送验证码 func (s *MockSMSService) SendVerificationCode(ctx context.Context, phone string, code string) error { s.logger.Info("Mock SMS sent", zap.String("phone", phone), zap.String("code", code)) return nil } // GenerateCode 生成验证码 func (s *MockSMSService) GenerateCode(length int) string { if length <= 0 { length = 6 } // 开发环境使用固定验证码便于测试 result := "" for i := 0; i < length; i++ { result += "1" } return result }