0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

用基于gin框架的Go語言來實現(xiàn)手機號發(fā)送短信驗證碼登錄

馬哥Linux運維 ? 來源:CSDN ? 作者:貓不吃魚呀 ? 2022-07-20 09:36 ? 次閱讀

現(xiàn)在大多數(shù)app或wap都實現(xiàn)了通過手機號獲取驗證碼進行驗證登錄,下面來看下用go來實現(xiàn)手機號發(fā)送短信驗證碼登錄的過程,基于的框架是gin 。

首先是短信服務(wù)商的申請,比如騰訊云、阿里云、網(wǎng)易易盾等,騰訊云自己申請個微信公眾號就行,然后申請相關(guān)的短信簽名、和短信模板,騰訊有100條試用喔。 具體的代碼實現(xiàn) 配置騰訊云短信服務(wù)的發(fā)送短信相關(guān)配置,具體可以參考騰訊云短信服務(wù)的api 文檔,進行配置


pYYBAGLXXCmAMMk3AABN_sggOds651.jpg
go 這里采用的是viper進行加載配置,相關(guān)的加載配置代碼如下 定義相關(guān)的配置結(jié)構(gòu)體,并加載到整個項目的總的options 配置結(jié)構(gòu)體中

// sms 發(fā)送短信的配置options
type 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
}

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ā)送驗證碼的實現(xiàn)

type SmsClient struct {
Credential *common.Credential
Region string
Cpf *profile.ClientProfile
Request 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ā)送短信驗證碼成功")
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.SmsSdkAppId
request.SignName = &options.SignName
request.TemplateId = &options.TemplateId
smsRequest := &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ā)送驗證碼的控制層,發(fā)送成功,并將此處的電話號碼和驗證碼保存到redis緩存中,用來登錄時候的驗證碼有效性的校驗

func (u *userService) SendPhoneCode(ctx context.Context, phone string) bool {
// 獲取配置參數(shù)
smsSetting := global.TencenSmsSetting
phoneSet := []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) { // 從緩存中獲取該手機號對應(yīng)的驗證碼是否匹配 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



審核編輯:劉清


聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • WAP
    WAP
    +關(guān)注

    關(guān)注

    0

    文章

    25

    瀏覽量

    34281
  • APP
    APP
    +關(guān)注

    關(guān)注

    33

    文章

    1557

    瀏覽量

    72153

原文標題:Go語言實現(xiàn)發(fā)送短信驗證碼并登錄

文章出處:【微信號:magedu-Linux,微信公眾號:馬哥Linux運維】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    告別短信驗證時代的先驅(qū)者

    創(chuàng)新性身份驗證方式。1. 傳統(tǒng)身份驗證方式 1) 短信驗證短信驗證實現(xiàn)流程:一般需要用戶在注冊過
    發(fā)表于 05-27 15:02

    如何用阿里大于發(fā)送短信?

    SendSmsRequest();try{ //必填:待發(fā)送手機號。支持以逗號分隔的形式進行批量調(diào)用,批量上限為1000個手機號碼,批量調(diào)用相對于單條調(diào)用及時性稍有延遲,驗證碼類型的
    發(fā)表于 02-03 16:08

    為什么短信驗證碼在我們生活中頻頻出現(xiàn)

    來說選擇不同平臺的效果會有所不同。如果選擇一個低成本、效果好、安全性高、操作方便的平臺管理用戶、短信驗證碼,平臺本身具有安全性高、不泄露用戶信息等優(yōu)點,對于企業(yè)來說是很重要的。而且企業(yè)短信
    發(fā)表于 04-16 23:12

    OpenHarmony端云一體化應(yīng)用開發(fā)快速入門練習(xí)(中)登錄認證

    一、登錄認證手機 可以在應(yīng)用中集成手機帳號認證方式,您的用戶可以使用“手機號碼+密碼”或者“手機號碼+
    發(fā)表于 06-20 17:05

    基于加密短信驗證碼的移動安全支付解決方案

    安全認證,并且利用客戶在服務(wù)器上注冊的用戶名、密碼和加密的交易驗證短信確保即使驗證碼密文泄漏,攻擊者也無法獲取驗證碼,從而杜絕了
    發(fā)表于 11-29 14:40 ?0次下載
    基于加密<b class='flag-5'>短信</b><b class='flag-5'>驗證碼</b>的移動安全支付解決方案

    驗證碼能保證真的安全嗎?

    驗證碼的世界,竟然……如此觸目驚心! 這年頭,無論支付、注冊、還是登錄各種端口,哪怕是保障用戶安全的諸多舉措
    的頭像 發(fā)表于 06-10 09:31 ?1.1w次閱讀

    短信驗證碼漏洞風(fēng)險多,安全系統(tǒng)待升級

    人在睡夢中,手機在身邊。是誰遠程偷看了短信驗證碼,還利用短信驗證碼完成了轉(zhuǎn)賬購物借貸等操作?據(jù)了解,這是不法分子通過“GSM劫持+
    發(fā)表于 08-18 11:06 ?1371次閱讀

    GSM協(xié)議漏洞被非法利用 “短信驗證碼”還安全嗎

    最近,手機有時無緣無故地收到短信驗證碼,但是本人并未進行任何操作。網(wǎng)上一查,發(fā)現(xiàn)這極有可能是最近鬧得沸沸揚揚的“截獲短信驗證碼盜刷案”。
    的頭像 發(fā)表于 09-08 09:04 ?4189次閱讀

    以一個真實網(wǎng)站的驗證碼為例,實現(xiàn)了基于一下KNN的驗證碼識別

    很多網(wǎng)站登錄都需要輸入驗證碼,如果要實現(xiàn)自動登錄就不可避免的要識別驗證碼。本文以一個真實網(wǎng)站的驗證碼
    的頭像 發(fā)表于 12-24 17:27 ?7666次閱讀

    黑客虛假谷歌驗證碼針對銀行發(fā)送惡意軟件

    黑客針對一家波蘭銀行,利用虛假谷歌reCAPTCHA驗證碼發(fā)送惡意軟件。
    的頭像 發(fā)表于 02-25 10:01 ?3325次閱讀

    拖動驗證碼的具體實現(xiàn)

    .驗證碼的一個功能就是規(guī)避機器的自動操作,所以我們需要通過軌跡判斷這個拖動過程是真實的人還是機器,因此我們需要記錄拖動的路徑,路徑經(jīng)過計算之后可以發(fā)送到后端進行進一步的分類,比如對
    的頭像 發(fā)表于 07-18 11:02 ?6604次閱讀
    拖動<b class='flag-5'>驗證碼</b>的具體<b class='flag-5'>實現(xiàn)</b>

    爬蟲實現(xiàn)目標網(wǎng)站驗證碼登陸

    在爬蟲訪問目標網(wǎng)站的過程中,很多網(wǎng)站為了避免被惡意訪問,需要設(shè)置驗證碼登錄,這樣是為了避免非人類的訪問。今天我們學(xué)習(xí)下如何使用Python爬蟲實現(xiàn)驗證碼
    發(fā)表于 12-11 15:27 ?2331次閱讀

    一個短信驗證碼爆破重置

    以前倒是遇到過不少四位數(shù)驗證碼爆破的,但是這種可以結(jié)合短信遍歷,一個短信驗證碼只能驗證三次的,最后能成功利用的還是第一次遇到,關(guān)鍵還是這里不
    的頭像 發(fā)表于 09-07 09:14 ?4779次閱讀

    Java 中驗證碼的使用

    今天我們講一下在 Java 中驗證碼的使用。 驗證碼生成 本效果是利用easy-captcha工具包實現(xiàn),首先需要添加相關(guān)依賴到pom.xml中,代碼如下: com .github.whvcse
    的頭像 發(fā)表于 09-25 11:11 ?795次閱讀
    Java 中<b class='flag-5'>驗證碼</b>的使用

    SpringBoot分布式驗證碼登錄方案

    傳統(tǒng)的項目大都是基于session交互的,前后端都在一個項目里面,比如傳統(tǒng)的SSH項目或者一些JSP系統(tǒng),當(dāng)前端頁面觸發(fā)到獲取驗證碼請求,可以將驗證碼里面的信息存在上下文中,所以登錄的時候只需要 用戶名、密碼、
    的頭像 發(fā)表于 10-12 17:34 ?606次閱讀
    SpringBoot分布式<b class='flag-5'>驗證碼</b><b class='flag-5'>登錄</b>方案