golang后端接入MOB的短信服务

2023-11-27 03:00

本文主要是介绍golang后端接入MOB的短信服务,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

背景:

初学golang,想和同学前后端分离做个小APP,我负责后端。
需要用到短信服务来做验证码登陆,选择了MobTech的SMS服务(一个月免费1W条,MOB牛逼!)

问题:

以前做的短信登陆逻辑如图:
在这里插入图片描述
MOB文档中给出了两种策略:
在这里插入图片描述
在这里插入图片描述
我感觉第一种后端不涉及验证过程的策略可能存在安全隐患,因为校验短信验证码的动作发生在前端,之后由开发者在前端回调后台的业务接口诸如登陆和注册。
那么在调用这一业务接口时,肯定需要前端引入某种加密策略,来确保对该接口的请求一定是前端经过完整的验证码流程后发起的,只有这样才能保证用户身份的正确。
在这种情况下,如果前端的加密策略泄露,可能导致不法分子伪装其他用户的身份进行登陆或其他权限相关操作,就糟糕了。

以上仅是我这个初学者结合以往经验的一点点猜测,既然这种模式存在于官方文档中,那肯定有足够安全的实现策略,不过我现在还不知道: (

我暂时就先用自己理解上觉得更安全、更顺手的第二种策略来实现。

在此先附上MobTech的SMS服务接入文档:
Mob文档中心 / SMSSDK

注册账号并创建应用、企业认证过程这里就不提了。
前端根据不同实现可以参考上述文档快速接入SDK。
后端如果要采用第二种策略,需要进行以下操作:

  1. 填入部署后端应用的服务器的ip
    在这里插入图片描述
  2. 对Mob提供的验证码校验接口进行封装
package smsimport ("encoding/json""errors""fmt""io/ioutil""net/http""net/url""strings"
)//短信服务功能封装//默认区号为中国(+86)
const DEFAULT_ZONE = "86"//MOB提供的验证码校验接口
const VERIFY_URL = "https://webapi.sms.mob.com/sms/verify"const APP_KEY = "xxxxxxxx"
const APP_SECRET = "xxxxxxxxxxxxxxxxxxxxxxxxxx"//校验收到的验证码
func VerifyCode(phone, code string) (bool, error) {//********************************************************//* 通过json的方式进行post请求的传参  在这里是不适用的!!!    *//********************************************************//contentType := "application/json"//data := mapToJSON(&map[string]interface{}{//	"phone":  phone,//	"code":   code,//	"appkey": "31db8a6381fb0",//	"zone":   DEFAULT_ZONE,//})//resp, err := http.Post(VERIFY_URL, contentType, strings.NewReader(data))urlValues := url.Values{"phone":  {phone},"code":   {code},"appkey": {APP_KEY},"zone":   {DEFAULT_ZONE},}reqBody:= urlValues.Encode()resp, err := http.Post(VERIFY_URL, "text/html",strings.NewReader(reqBody))if err != nil {fmt.Printf("post failed, err:%v\n", err)return false, err}defer resp.Body.Close()b, err := ioutil.ReadAll(resp.Body)if err != nil {fmt.Printf("get resp failed, err:%v\n", err)return false, err}//json序列化成map 解析MOB验证接口的返回值var tempMap map[string]interface{}err = json.Unmarshal([]byte(b), &tempMap)if err != nil {fmt.Printf("parse resp failed, err:%v\n", err)return false, err}fmt.Println("接口返回的状态码是:",tempMap["status"])fmt.Println("接口返回的message是:",tempMap["error"])//根据接口返回状态码 判断验证码结果switch int(tempMap["status"].(float64)) {case 200:return true, nildefault:return false,errors.New(tempMap["error"].(string))}
}//map转json
func mapToJSON(tempMap *map[string]interface{}) string {data, err := json.Marshal(tempMap)if err != nil {panic(err)}return string(data)
}

注意,这里有一个坑!
在golang里,post请求传参有三种常见的方式:

  • conten-type : text/html 这种实际上是把参数拼接到url上)

  • conten-type : application/x-www-form-urlencoded

  • conten-type : application/json

    对应到golang代码中有以下三种写法:

  •  	  urlValues := url.Values{"name":{"zhaofan"},"age":{"23"},}reqBody:= urlValues.Encode()resp, _ := http.Post("http://xxxxxx", "text/html",strings.NewReader(reqBody))body,_:= ioutil.ReadAll(resp.Body)fmt.Println(string(body))
    
  •      urlValues := url.Values{}urlValues.Add("name","zhaofan")urlValues.Add("age","22")resp, _ := http.PostForm("http://httpbin.org/post",urlValues)body, _ := ioutil.ReadAll(resp.Body)fmt.Println(string(body))
    
  •  	 data := mapToJSON(&map[string]interface{}{"phone":  phone,"code":   code,"appkey": "31db8a6381fb0","zone":   DEFAULT_ZONE,})resp, _:= http.Post(VERIFY_URL, contentType, strings.NewReader(data))body, _ := ioutil.ReadAll(resp.Body)fmt.Println(string(body))//map转jsonfunc mapToJSON(tempMap *map[string]interface{}) string {data, err := json.Marshal(tempMap)if err != nil {panic(err)}return string(data)}
    

当我使用第三种JSON传参的时候,MOB的验证接口一直给我报405 AppKey为空
改用第一种、第二种传参方式之后都能够正常调用。
估计是mob提供的这个接口在解析参数时不支持json传参。

这也体现出了gin框架在http请求参数解析时的强大之处:
只需要在声明接收参数的结构体时,给对应字段添加几个“注解”
(暂时不知道这个小引号的学名,先这么叫它^^)
再结合func (c *Context) ShouldBind(obj interface{}) error就能完美实现httpRequest的参数获取。

//接受参数的实体
type Verify struct {Phone    string     `form:"phone" json:"phone" binding:"required"`Code     string 	`form:"code" json:"code" binding:"required"`
}var verify Verify	//用于装载参数的结构体
if err := c.ShouldBind(&verify); err == nil {...}//读取参数后的业务逻辑
  1. 给前端提供校验接口,可以整合自己的登陆或注册等等业务逻辑
//接受参数的实体
type Verify struct {Phone    string `form:"phone" json:"phone" binding:"required"`Code string 	`form:"code" json:"code" binding:"required"`
}
//这是一个功能接口 POST类型 路由为 '/phone' 用于手机或者注册
func phone(c *gin.Context) {//获取请求参数...业务逻辑var verify Verifyif err := c.ShouldBind(&verify); err == nil {fmt.Printf("verify info:%#v\n", verify)//1、校验验证码isCorrect,_ := sms.VerifyCode(verify.Phone,verify.Code)//验证码正确if isCorrect {//2、校验手机号是否存在 不存在则先注册再返回token 存在则直接返回tokenbyPhone, _ := service.GetUserByPhone(verify.Phone)if byPhone==(bean.User{}) {//用户不存在c.JSON(http.StatusOK,response.Ok("新用户注册成功",nil))}else{//用户已存在c.JSON(http.StatusOK,response.Ok("登陆成功",nil))}}else{//验证码不正确c.JSON(http.StatusOK,response.Fail("验证码错误"))}} else {c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})}
}



收工!

在这里插入图片描述

这篇关于golang后端接入MOB的短信服务的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/426906

相关文章

SpringBoot服务获取Pod当前IP的两种方案

《SpringBoot服务获取Pod当前IP的两种方案》在Kubernetes集群中,SpringBoot服务获取Pod当前IP的方案主要有两种,通过环境变量注入或通过Java代码动态获取网络接口IP... 目录方案一:通过 Kubernetes Downward API 注入环境变量原理步骤方案二:通过

Golang 日志处理和正则处理的操作方法

《Golang日志处理和正则处理的操作方法》:本文主要介绍Golang日志处理和正则处理的操作方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考... 目录1、logx日志处理1.1、logx简介1.2、日志初始化与配置1.3、常用方法1.4、配合defer

如何搭建并配置HTTPD文件服务及访问权限控制

《如何搭建并配置HTTPD文件服务及访问权限控制》:本文主要介绍如何搭建并配置HTTPD文件服务及访问权限控制的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、安装HTTPD服务二、HTTPD服务目录结构三、配置修改四、服务启动五、基于用户访问权限控制六、

golang float和科学计数法转字符串的实现方式

《golangfloat和科学计数法转字符串的实现方式》:本文主要介绍golangfloat和科学计数法转字符串的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望... 目录golang float和科学计数法转字符串需要对float转字符串做处理总结golang float

golang实现延迟队列(delay queue)的两种实现

《golang实现延迟队列(delayqueue)的两种实现》本文主要介绍了golang实现延迟队列(delayqueue)的两种实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的... 目录1 延迟队列:邮件提醒、订单自动取消2 实现2.1 simplChina编程e简单版:go自带的time

Golang实现Redis分布式锁(Lua脚本+可重入+自动续期)

《Golang实现Redis分布式锁(Lua脚本+可重入+自动续期)》本文主要介绍了Golang分布式锁实现,采用Redis+Lua脚本确保原子性,持可重入和自动续期,用于防止超卖及重复下单,具有一定... 目录1 概念应用场景分布式锁必备特性2 思路分析宕机与过期防止误删keyLua保证原子性可重入锁自动

golang 对象池sync.Pool的实现

《golang对象池sync.Pool的实现》:本文主要介绍golang对象池sync.Pool的实现,用于缓存和复用临时对象,以减少内存分配和垃圾回收的压力,下面就来介绍一下,感兴趣的可以了解... 目录sync.Pool的用法原理sync.Pool 的使用示例sync.Pool 的使用场景注意sync.

golang中slice扩容的具体实现

《golang中slice扩容的具体实现》Go语言中的切片扩容机制是Go运行时的一个关键部分,它确保切片在动态增加元素时能够高效地管理内存,本文主要介绍了golang中slice扩容的具体实现,感兴趣... 目录1. 切片扩容的触发append 函数的实现2. runtime.growslice 函数gro

golang实现动态路由的项目实践

《golang实现动态路由的项目实践》本文主要介绍了golang实现动态路由项目实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习... 目录一、动态路由1.结构体(数据库的定义)2.预加载preload3.添加关联的方法一、动态路由1

Golang interface{}的具体使用

《Golanginterface{}的具体使用》interface{}是Go中可以表示任意类型的空接口,本文主要介绍了Golanginterface{}的具体使用,具有一定的参考价值,感兴趣的可以了... 目录一、什么是 interface{}?定义形China编程式:二、interface{} 有什么特别的?✅