<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

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

          共 6152字,需瀏覽 13分鐘

           ·

          2022-07-25 09:47


          現(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 。


          首先是短信服務(wù)商的申請(qǐng),比如騰訊云、阿里云、網(wǎng)易易盾等,騰訊云自己申請(qǐng)個(gè)微信公眾號(hào)就行,然后申請(qǐng)相關(guān)的短信簽名、和短信模板,騰訊有100條試用喔。
          具體的代碼實(shí)現(xiàn)
          配置騰訊云短信服務(wù)的發(fā)送短信相關(guān)配置,具體可以參考騰訊云短信服務(wù)的api 文檔,進(jìn)行配置
          sms: secret-key: #秘鑰,可在控制臺(tái)查詢 secret-id: #秘鑰id ,可在控制臺(tái)查詢 sms-sdk-app-id: #應(yīng)用id Sign-name: #申請(qǐng)的簽名 template-id: #模板id
          go 這里采用的是viper進(jìn)行加載配置,相關(guān)的加載配置代碼如下
          定義相關(guān)的配置結(jié)構(gòu)體,并加載到整個(gè)項(xiàng)目的總的options 配置結(jié)構(gòu)體中
          // 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}
          viper加載配置的代碼如下
          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}}

          下面是發(fā)送驗(yàn)證碼的實(shí)現(xiàn)
          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}
          定義發(fā)送的client,這里采用function option 的編程模式來初始化發(fā)送的client.和發(fā)送的request,request的代碼如下
          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)}}
          創(chuàng)建發(fā)送驗(yàn)證碼的控制層,發(fā)送成功,并將此處的電話號(hào)碼和驗(yàn)證碼保存到redis緩存中,用來登錄時(shí)候的驗(yàn)證碼有效性的校驗(yàn)
          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
          }
          后面是通過手機(jī)驗(yàn)證碼進(jìn)行登錄的流程
          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)歸原作者所有,侵刪)


          瀏覽 28
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  中文字幕日韩成人电影 | 日韩高跟视频在线播放 | 亚洲男人的天堂视频网在线观看+720P | 一级黄色视频日逼片 | a网站在线观看 |