0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

用基于gin框架的Go语言来实现手机号发送短信验证码登录

马哥Linux运维 来源:CSDN 作者:猫不吃鱼呀 2022-07-20 09:36 次阅读

现在大多数app或wap都实现了通过手机号获取验证码进行验证登录,下面来看下用go来实现手机号发送短信验证码登录的过程,基于的框架是gin 。

首先是短信服务商的申请,比如腾讯云、阿里云、网易易盾等,腾讯云自己申请个微信公众号就行,然后申请相关的短信签名、和短信模板,腾讯有100条试用喔。 具体的代码实现 配置腾讯云短信服务的发送短信相关配置,具体可以参考腾讯云短信服务的api 文档,进行配置


pYYBAGLXXCmAMMk3AABN_sggOds651.jpg
go 这里采用的是viper进行加载配置,相关的加载配置代码如下 定义相关的配置结构体,并加载到整个项目的总的options 配置结构体中

// sms 发送短信的配置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
}
}

下面是发送验证码的实现

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("发送短信失败:%s,requestId:%s", err)
return false

}
logger.Info("发送短信验证码成功")
return true
}

定义发送的client,这里采用function option 的编程模式来初始化发送的client.和发送的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)
}
}

创建发送验证码的控制层,发送成功,并将此处的电话号码和验证码保存到redis缓存中,用来登录时候的验证码有效性的校验

func (u *userService) SendPhoneCode(ctx context.Context, phone string) bool {
// 获取配置参数
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) { // 从缓存中获取该手机号对应的验证码是否匹配 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



审核编辑:刘清


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • WAP
    WAP
    +关注

    关注

    0

    文章

    25

    浏览量

    34346
  • APP
    APP
    +关注

    关注

    33

    文章

    1568

    浏览量

    72361

原文标题:Go语言实现发送短信验证码并登录

文章出处:【微信号:magedu-Linux,微信公众号:马哥Linux运维】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    告别短信验证时代的先驱者

    创新性身份验证方式。1. 传统身份验证方式 1) 短信验证短信验证实现流程:一般需要用户在注册过
    发表于 05-27 15:02

    如何用阿里大于发送短信

    SendSmsRequest();try{ //必填:待发送手机号。支持以逗号分隔的形式进行批量调用,批量上限为1000个手机号码,批量调用相对于单条调用及时性稍有延迟,验证码类型的
    发表于 02-03 16:08

    为什么短信验证码在我们生活中频频出现

    来说选择不同平台的效果会有所不同。如果选择一个低成本、效果好、安全性高、操作方便的平台管理用户、短信验证码,平台本身具有安全性高、不泄露用户信息等优点,对于企业来说是很重要的。而且企业短信
    发表于 04-16 23:12

    OpenHarmony端云一体化应用开发快速入门练习(中)登录认证

    一、登录认证手机 可以在应用中集成手机帐号认证方式,您的用户可以使用“手机号码+密码”或者“手机号码+
    发表于 06-20 17:05

    基于加密短信验证码的移动安全支付解决方案

    安全认证,并且利用客户在服务器上注册的用户名、密码和加密的交易验证短信确保即使验证码密文泄漏,攻击者也无法获取验证码,从而杜绝了
    发表于 11-29 14:40 0次下载
    基于加密<b class='flag-5'>短信</b><b class='flag-5'>验证码</b>的移动安全支付解决方案

    验证码能保证真的安全吗?

    验证码的世界,竟然……如此触目惊心! 这年头,无论支付、注册、还是登录各种端口,哪怕是保障用户安全的诸多举措
    的头像 发表于 06-10 09:31 1.1w次阅读

    短信验证码漏洞风险多,安全系统待升级

    人在睡梦中,手机在身边。是谁远程偷看了短信验证码,还利用短信验证码完成了转账购物借贷等操作?据了解,这是不法分子通过“GSM劫持+
    发表于 08-18 11:06 1424次阅读

    GSM协议漏洞被非法利用 “短信验证码”还安全吗

    最近,手机有时无缘无故地收到短信验证码,但是本人并未进行任何操作。网上一查,发现这极有可能是最近闹得沸沸扬扬的“截获短信验证码盗刷案”。
    的头像 发表于 09-08 09:04 4259次阅读

    以一个真实网站的验证码为例,实现了基于一下KNN的验证码识别

    很多网站登录都需要输入验证码,如果要实现自动登录就不可避免的要识别验证码。本文以一个真实网站的验证码
    的头像 发表于 12-24 17:27 7746次阅读

    黑客虚假谷歌验证码针对银行发送恶意软件

    黑客针对一家波兰银行,利用虚假谷歌reCAPTCHA验证码发送恶意软件。
    的头像 发表于 02-25 10:01 3376次阅读

    拖动验证码的具体实现

    .验证码的一个功能就是规避机器的自动操作,所以我们需要通过轨迹判断这个拖动过程是真实的人还是机器,因此我们需要记录拖动的路径,路径经过计算之后可以发送到后端进行进一步的分类,比如对
    的头像 发表于 07-18 11:02 6760次阅读
    拖动<b class='flag-5'>验证码</b>的具体<b class='flag-5'>实现</b>

    爬虫实现目标网站验证码登陆

    在爬虫访问目标网站的过程中,很多网站为了避免被恶意访问,需要设置验证码登录,这样是为了避免非人类的访问。今天我们学习下如何使用Python爬虫实现验证码
    发表于 12-11 15:27 2407次阅读

    一个短信验证码爆破重置

    以前倒是遇到过不少四位数验证码爆破的,但是这种可以结合短信遍历,一个短信验证码只能验证三次的,最后能成功利用的还是第一次遇到,关键还是这里不
    的头像 发表于 09-07 09:14 4972次阅读

    Java 中验证码的使用

    今天我们讲一下在 Java 中验证码的使用。 验证码生成 本效果是利用easy-captcha工具包实现,首先需要添加相关依赖到pom.xml中,代码如下: com .github.whvcse
    的头像 发表于 09-25 11:11 979次阅读
    Java 中<b class='flag-5'>验证码</b>的使用

    SpringBoot分布式验证码登录方案

    传统的项目大都是基于session交互的,前后端都在一个项目里面,比如传统的SSH项目或者一些JSP系统,当前端页面触发到获取验证码请求,可以将验证码里面的信息存在上下文中,所以登录的时候只需要 用户名、密码、
    的头像 发表于 10-12 17:34 685次阅读
    SpringBoot分布式<b class='flag-5'>验证码</b><b class='flag-5'>登录</b>方案