Go语言实现发送短信验证码并登录

现在大多数app或wap都实现了通过手机号获取验证码进行验证登录,下面来看下用go来实现手机号发送短信验证码登录的过程,基于的框架是gin 。
sms:secret-key:secret-id:sms-sdk-app-id:Sign-name:template-id:
// sms 发送短信的配置optionstype SmsOptions struct {SecretKey string `json:"secret-key,omitempty" mapstructure:"secret-key"`SecretId string `json:"secret-id,omitempty" mapstructure:"secret-id"`SmsSdkAppId string `json:"sms-sdk-app-id,omitempty" mapstructure:"sms-sdk-app-id"`SignName string `json:"sign-name,omitempty" mapstructure:"sign-name"`TemplateId string `json:"template-id,omitempty" mapstructure:"template-id"`}func NewSmsOptions() *SmsOptions {return &SmsOptions{SecretKey: "",SecretId: "",SmsSdkAppId: "",SignName: "",TemplateId: "",}}// 这为项目总的一个options配置,项目启动的时候会将yaml中的加载到option中type Options struct {GenericServerRunOptions *genericoptions.ServerRunOptions `json:"server" mapstructure:"server"`MySQLOptions *genericoptions.MySQLOptions `json:"mysql" mapstructure:"mysql"`InsecuresServing *genericoptions.InsecureServerOptions `json:"insecure" mapstructure:"insecure"`Log *logger.Options `json:"log" mapstructure:"log"`RedisOptions *genericoptions.RedisOptions `json:"redis" mapstructure:"redis"`SmsOptions *genericoptions.SmsOptions `json:"sms" mapstructure:"sms"`}func NewOptions() *Options {o:=Options{GenericServerRunOptions: genericoptions.NewServerRunOptions(),MySQLOptions: genericoptions.NewMySQLOptions(),InsecuresServing: genericoptions.NewInsecureServerOptions(),RedisOptions: genericoptions.NewRedisOptions(),Log: logger.NewOptions(),SmsOptions: genericoptions.NewSmsOptions(),}return &o}
func AddConfigToOptions(options *options.Options) error {viper.SetConfigName("config")viper.AddConfigPath("config/")viper.SetConfigType("yaml")err := viper.ReadInConfig()if err != nil {return err}optDecode := viper.DecodeHook(mapstructure.ComposeDecodeHookFunc(mapstructure.StringToTimeDurationHookFunc(), StringToByteSizeHookFunc()))err = viper.Unmarshal(options, optDecode)fmt.Println(options)if err != nil {return err}return nil}func StringToByteSizeHookFunc() mapstructure.DecodeHookFunc {return func(f reflect.Type,t reflect.Type, data interface{}) (interface{}, error) {if f.Kind() != reflect.String {return data, nil}if t != reflect.TypeOf(datasize.ByteSize(5)) {return data, nil}raw := data.(string)result := new(datasize.ByteSize)result.UnmarshalText([]byte(raw))return result.Bytes(), nil}}
type SmsClient struct {Credential *common.CredentialRegion stringCpf *profile.ClientProfileRequest SmsRequest}type Option func(*SmsClient)func NewSmsClient(options ...func(client *SmsClient)) *SmsClient {client := &SmsClient{Region: "ap-guangzhou",Cpf: profile.NewClientProfile(),}for _, option := range options {option(client)}return client}func WithRequest(request SmsRequest) Option {return func(smsClient *SmsClient) {smsClient.Request = request}}func WithCredential(options options.SmsOptions) Option {return func(smsClient *SmsClient) {smsClient.Credential = common.NewCredential(options.SecretId, options.SecretKey)}}func WithCpfReqMethod(method string) Option {return func(smsClient *SmsClient) {smsClient.Cpf.HttpProfile.ReqMethod = method}}func WithCpfReqTimeout(timeout int) Option {return func(smsClient *SmsClient) {smsClient.Cpf.HttpProfile.ReqTimeout = timeout}}func WithCpfSignMethod(method string) Option {return func(smsClient *SmsClient) {smsClient.Cpf.SignMethod = method}}func (s *SmsClient) Send() bool {sendClient, _ := sms.NewClient(s.Credential, s.Region, s.Cpf)_, err := sendClient.SendSms(s.Request.request)if _, ok := err.(*errors.TencentCloudSDKError); ok {logger.Warnf("An API error has returned: %s", err)return false}if err != nil {logger.Warnf("发送短信失败:%s,requestId:%s", err)return false}logger.Info("发送短信验证码成功")return true}
type SmsRequest struct {request *sms.SendSmsRequest}func NewSmsRequest(options *options.SmsOptions, withOptions ...func(smsRequest *SmsRequest)) *SmsRequest {request := sms.NewSendSmsRequest()request.SmsSdkAppId = &options.SmsSdkAppIdrequest.SignName = &options.SignNamerequest.TemplateId = &options.TemplateIdsmsRequest := &SmsRequest{request: request}for _, option := range withOptions {option(smsRequest)}return smsRequest}type RequestOption func(*SmsRequest)func WithPhoneNumberSet(phoneSet []string) RequestOption {return func(smsRequest *SmsRequest) {smsRequest.request.PhoneNumberSet = common.StringPtrs(phoneSet)}}func WithTemplateParamSet(templateSet []string) RequestOption {return func(smsRequest *SmsRequest) {smsRequest.request.TemplateParamSet = common.StringPtrs(templateSet)}}
func (u *userService) SendPhoneCode(ctx context.Context, phone string) bool {// 获取配置参数smsSetting := global.TencenSmsSettingphoneSet := []string{phone}// 随机生成6位的验证码var randCode string = fmt.Sprintf("%06v", rand.New(rand.NewSource(time.Now().UnixNano())).Int31n(1000000))templateSet := []string{randCode, "60"}smsRequest := tencenSms.NewSmsRequest(smsSetting, tencenSms.WithPhoneNumberSet(phoneSet), tencenSms.WithTemplateParamSet(templateSet))smsClient := tencenSms.NewSmsClient(tencenSms.WithRequest(*smsRequest), tencenSms.WithCredential(*smsSetting))go smsClient.Send()// 将验证码和手机号保存到redis中_ = u.cache.UserCaches().SetSendPhoneCodeCache(ctx, phone, randCode)return true}
func (u *userService) LoginByPhoneCode(ctx context.Context, phone string, phoneCode string) (*model.User,error) {// 从缓存中获取该手机号对应的验证码是否匹配cacheCode, err :=u.cache.UserCaches().GetSendPhoneCodeFromCache(ctx,phone)if err != nil {return nil, errors.WithCode(code.ErrUserPhoneCodeExpire,err.Error())}if cacheCode!=phoneCode {return nil,errors.WithCode(code.ErrUserPhoneCodeMiss,"")}return &model.User{Nickname: "lala",}, nil}链接: (版权归原作者所有,侵删)
评论
