Go語言實(shí)現(xiàn)發(fā)送短信驗(yàn)證碼并登錄

現(xiàn)在大多數(shù)app或wap都實(shí)現(xiàn)了通過手機(jī)號(hào)獲取驗(yàn)證碼進(jìn)行驗(yàn)證登錄,下面來看下用go來實(shí)現(xiàn)手機(jī)號(hào)發(fā)送短信驗(yàn)證碼登錄的過程,基于的框架是gin 。
sms:secret-key:secret-id:sms-sdk-app-id:Sign-name:template-id:
// sms 發(fā)送短信的配置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: "",}}// 這為項(xiàng)目總的一個(gè)options配置,項(xiàng)目啟動(dòng)的時(shí)候會(huì)將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("發(fā)送短信失敗:%s,requestId:%s", err)return false}logger.Info("發(fā)送短信驗(yàn)證碼成功")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 {// 獲取配置參數(shù)smsSetting := global.TencenSmsSettingphoneSet := []string{phone}// 隨機(jī)生成6位的驗(yàn)證碼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()// 將驗(yàn)證碼和手機(jī)號(hào)保存到redis中_ = u.cache.UserCaches().SetSendPhoneCodeCache(ctx, phone, randCode)return true}
func (u *userService) LoginByPhoneCode(ctx context.Context, phone string, phoneCode string) (*model.User,error) {// 從緩存中獲取該手機(jī)號(hào)對(duì)應(yīng)的驗(yàn)證碼是否匹配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}鏈接: (版權(quán)歸原作者所有,侵刪)
評(píng)論
圖片
表情
