package sms import ( "context" "encoding/json" "fmt" "strings" openapi "github.com/alibabacloud-go/darabonba-openapi/v2/utils" dysms "github.com/alibabacloud-go/dysmsapi-20170525/v5/client" "github.com/alibabacloud-go/tea/dara" "go.uber.org/zap" ) type AliyunConfig struct { AccessKeyID string AccessKeySecret string Endpoint string SignName string LoginTemplateCode string } type AliyunProvider struct { client *dysms.Client signName string loginTemplateCode string log *zap.Logger } func NewAliyunProvider(cfg AliyunConfig, log *zap.Logger) (*AliyunProvider, error) { cfg.Endpoint = strings.TrimSpace(cfg.Endpoint) if cfg.Endpoint == "" { cfg.Endpoint = "dysmsapi.aliyuncs.com" } if strings.TrimSpace(cfg.AccessKeyID) == "" || strings.TrimSpace(cfg.AccessKeySecret) == "" || strings.TrimSpace(cfg.SignName) == "" || strings.TrimSpace(cfg.LoginTemplateCode) == "" { return nil, ErrProviderConfigInvalid } client, err := dysms.NewClient(&openapi.Config{ AccessKeyId: dara.String(strings.TrimSpace(cfg.AccessKeyID)), AccessKeySecret: dara.String(strings.TrimSpace(cfg.AccessKeySecret)), Endpoint: dara.String(cfg.Endpoint), }) if err != nil { return nil, err } return &AliyunProvider{ client: client, signName: strings.TrimSpace(cfg.SignName), loginTemplateCode: strings.TrimSpace(cfg.LoginTemplateCode), log: log, }, nil } func (p *AliyunProvider) SendLoginCode(ctx context.Context, phone string, code string) error { params, err := json.Marshal(map[string]string{"code": code}) if err != nil { return err } req := &dysms.SendSmsRequest{} req.SetPhoneNumbers(phone) req.SetSignName(p.signName) req.SetTemplateCode(p.loginTemplateCode) req.SetTemplateParam(string(params)) resp, err := p.client.SendSmsWithContext(ctx, req, &dara.RuntimeOptions{}) if err != nil { return fmt.Errorf("aliyun sms send failed: %w", err) } if resp == nil || resp.Body == nil { return fmt.Errorf("aliyun sms empty response") } resultCode := dara.StringValue(resp.Body.Code) if resultCode != "OK" { resultMessage := dara.StringValue(resp.Body.Message) providerErr := &ProviderError{Code: resultCode, Message: resultMessage} if resultCode == "isv.BUSINESS_LIMIT_CONTROL" { providerErr.Err = ErrProviderRateLimited } return providerErr } if p.log != nil { p.log.Debug( "短信发送成功", zap.String("phone", maskPhone(phone)), zap.String("provider_request_id", dara.StringValue(resp.Body.RequestId)), ) } return nil } func maskPhone(phone string) string { if len(phone) < 7 { return phone } return phone[:3] + "****" + phone[len(phone)-4:] }