集成第三方發送短信
介紹
用戶登錄
用戶登錄有兩種方式: 短信登錄,密碼登錄
短信登錄是使用手機號和驗證碼進行登錄
短信平台
很多雲平台,比如阿里雲,騰訊雲,七牛雲等雲廠商,向程序開發者提供了短信驗證碼套餐服務。借助雲平台的短信服務,程序開發者可以非常簡單方便的將短信服務集成到自己的程序中。
我們以接入和集成阿里雲的短信服務sdk為例, 如果需要申請騰訊雲短信服務可以看我另外寫的一篇blog,使用兩者都差不多
https://www.cnblogs.com/you-men/p/13088949.html
阿里雲短信服務集成-登錄阿里雲
登錄阿里雲
登錄阿里雲:https://www.aliyun.com/
選擇短信服務模塊:https://www.aliyun.com/product/sms
注明:雲平台的短信服務是收費的,有不同類別的套餐。開發者可以按照自己的需求進行選擇。如下圖:
Go短信服務SDK
可以訪問https://api.aliyun.com/?spm=5176.12207334.0.0.54d71cbe3NE29f#/?product=Dysmsapi&lang=GO查看go語言版本的短信服務sdk代碼。
安裝阿里雲GO SDK
go get github.com/aliyun/alibaba-cloud-sdk-go
創建簽名和短信模板
在使用go sdk集成短息服務之前,需要首先創建短信簽名和短信模板。
簽名:短信簽名是短信服務提供的一種快捷、方便的個性化簽名方式。當發送短信時,短信平台會根據設置,在短信內容里附加個性簽名,再發送給指定手機號碼。比如,下圖紅框中的"招商銀行”就是這條短信的簽名,用以標識發送者的類別等內容。
在阿里雲后台的短信服務控制面板的左側功能欄中,選擇國內消息,如下圖所示,然后選擇簽名管理的TAB,然后選擇添加簽名,可以創建新的短信簽名。如下圖:
短信模板:短信模版,即具體發送的短信內容。短信模版可以支持驗證碼、短信通知、推廣短信三種模式。驗證碼和短信通知,通過變量替換實現個性短信定制。
與創建簽名同理,可以在模板管理TAB中,選擇添加模板,用來創建新的短信模板。創建完成后,會進行審核。
創建成功后的短信模板CODE需要記住,后續會使用到
在短信服務管理平台的概覽界面,可以選擇AccessKey按鈕進行創建集成短信服務所需要的AccessKey和AccessKeySecret。
程序中集成短信服務
client, err := dysmsapi.NewClientWithAccessKey(smsConfig.RegionId, smsConfig.AppKey, smsConfig.AppSecret)
if err != nil {
toolbox.Error(err.Error())
return ""
}
request := dysmsapi.CreateSendSmsRequest()
request.Scheme = "https"
request.SignName = smsConfig.SignName
request.TemplateCode = smsConfig.TemplateCode
request.PhoneNumbers = phone
par, err := json.Marshal(map[string]interface{}{
"code": code,
})
request.TemplateParam = string(par)
response, err := client.SendSms(request)
fmt.Println( response)
if err != nil {
toolbox.Error(err.Error())
return ""
}
我們通過上述核心代碼程序,完成阿里雲短信服務的集成。其中:
- SignName:在阿里雲后台創建的前名,必傳參數。
- TemplateCode:在阿里雲后台創建的短信模板ID,必傳參數。
- PhoneNumbers:接收短信的手機號碼,必傳參數。
創建阿里雲短信服務sdk的client時,需要傳regionID、appKey、accessKeySecret三個參數。regionID表示的是區域ID,可以填寫cn-hangzhou。
創建Controller解析請求
無論是短信登錄,還是用戶名和密碼登錄,均屬於用戶功能模塊。因此,創建MemberController用於解析用戶模塊的各個請求:
package controller
import (
"CloudRestaurant/service"
"fmt"
"github.com/gin-gonic/gin"
)
type MemberController struct {}
func (mc *MemberController) Router(engine *gin.Engine) {
engine.GET("/api/sendcode",mc.sendSmsCode)
}
// http://localhost:8090/api/sendcode?phone=18621048481
func (mc *MemberController) sendSmsCode(c *gin.Context) {
// 發送驗證碼
phone,exist := c.GetQuery("phone")
fmt.Println(phone,"phone --->")
if !exist {
c.JSON(200,map[string]interface{}{
"code":0,
"msg":"參數解析失敗",
})
return
}
ms := service.MemberService{}
isSend := ms.Sendcode(phone)
if isSend {
c.JSON(200,map[string]interface{}{
"code":1,
"msg":"發送成功",
})
return
}
c.JSON(200,map[string]interface{}{
"code":0,
"msg":"發送失敗",
})
}
創建用戶控制層程序MemberController,使用GET方法解析客戶端發送短信驗證碼的請求,請求接口為:/api/sendcode,同時指定sendSmsCode方法處理接口請求。
在實際的開發中,程序功能往往是分層來進行開發的,controller層只負責控制和處理接口請求的邏輯,具體的功能調用,往往由另外稱為service層的功能服務層來進行實現。
創建service層
在service層中,依然按照模塊化開發的理念,將用戶模塊的服務統一由UserServicej進行提供。因此,創建MemberService,並提供SendCode方法。
package service
import (
"CloudRestaurant/tool"
"encoding/json"
"fmt"
"github.com/aliyun/alibaba-cloud-sdk-go/services/dysmsapi"
"github.com/wonderivan/logger"
"math/rand"
"time"
)
type MemberService struct {
}
func (ms *MemberService) Sendcode(phone string) bool {
// 1.產生一個驗證碼
code := fmt.Sprintf("%06v",rand.New(rand.NewSource(time.Now().UnixNano())).Int31n(1000000))
// 2.調用阿里雲服務
config := tool.GetConfig().Sms
client, err := dysmsapi.NewClientWithAccessKey(config.RegionId, config.AppKey, config.AppSecret)
if err != nil {
logger.Error(err.Error())
return false
}
request := dysmsapi.CreateSendSmsRequest()
request.Scheme = "https"
request.SignName = config.SignName
request.TemplateCode = config.TemplateCode
request.PhoneNumbers = phone
par,err := json.Marshal(map[string]interface{}{
"code":code,
})
request.TemplateParam = string(par)
response,err :=client.SendSms(request)
fmt.Println(response,"response --->")
if err != nil {
logger.Error(err.Error())
return false
}
// 3. 接受返回結果,並判斷發送狀態
if response.Code == "OK" {
return true
}
return false
}
測試
在postman中, 使用/api/sendcode接口進行測試,詳細url如下:
http://localhost:8090/api/sendcode?phone=13167582436
然后就能在手機端收到驗證碼
創建數據庫和數據表
上面已經接入了第三方的短信服務SDK功能,可以接受短信驗證碼。在用戶接受到驗證碼以后,輸入驗證碼進行登錄,我們需要驗證用戶輸入的驗證碼是否正確。
因此,我們需要將發送過的驗證碼通過持久化的方式保存下來,方便我們進行校驗。
我們選擇通過數據庫來存儲用戶手機驗證碼。
xorm介紹及安裝
在項目開發過程中,我們會使用一些成熟的框架來操作數據庫。xorm就是一個比較流行的數據庫操作orm框架。
安裝xorm
go get github.com/go-xorm/xorm
安裝Mysql驅動
go get github.com/go-sql-driver/mysql
連接數據庫
在連接數據庫之前,首先要創建數據庫。在mysql中創建cloudrestaurant數據庫:
create database cloudrestaurant;
創建完數據庫並安裝好xorm庫以后,使用xorm進行連接數據庫
import (
"github.com/go-xorm/xorm"
_ "github.com/go-sql-driver/mysql"
)
database := cfg.Database
conn := database.User + ":" + database.Password + "@tcp(" + database.Host + ":" + database.Port + ")/" + database.DbName + "?charset=" + database.Charset
engine, err := xorm.NewEngine(database.Driver, conn)
if err != nil {
return nil, err
}
連接數據庫有些參數需要自己指定,比如說驅動類型,登錄數據庫的用戶名,密碼,數據庫名等。將這些變量配置在app.json配置文件中,如下所示:
{
"database": {
"driver": "mysql",
"user": "root",
"password": "12345678",
"host": "127.0.0.1",
"port": "3306",
"db_name": "cloudrestaurant",
"charset": "utf8mb4",
"show_sql": true
}
}
在Config結構體中添加對database的解析
type Config struct {
AppName string `json:"app_name"`
AppMode string `json:"app_mode"`
AppHost string `json:"app_host"`
AppPort string `json:"app_port"`
Database DatabaseConfig `json:"database"`
Sms SmsConfig `json:"sms"`
}
type DatabaseConfig struct {
Driver string `json:"driver"`
User string `json:"user"`
Password string `json:"password"`
Host string `json:"host"`
Port string `json:"port"`
DbName string `json:"db_name"`
Charset string `json:"charset"`
ShowSql bool `json:"show_sql"`
}
創建SmsCode
要存儲驗證碼,需要在數據庫中創建表結構進行存儲。我們可以創建SmsCode結構體,並通過tag設置數據庫字段約束,具體的SmsCode定義如下:
package model
type SmsCode struct {
Id int64 `xorm:"pk autoincr" json:"id"`
Phone string `xorm:"varchar(11)" json:"phone"`
BizId string `xorm:"varchar(30)" json:"biz_id"`
Code string `xorm:"varchar(4)" json:"code"`
CreateTime int64 `xorm:"bigint" json:"create_time"`
}
通過tag的xorm設置字段數據類型以及約束。
- pk:表示主鍵
- autoinc:表示自增
- bigint:整形變量
- varchar:字符串類型
Sync2同步生成數據庫表
可以調用engine.Sync2方法,將結構體類型同步映射到數據庫中,生成數據庫表。
err = engine.Sync2(new(model.SmsCode))
if err != nil {
return nil, err
}
將驗證碼數據保存到數據庫
在MemberService的SendCode方法,添加保存驗證碼到數據庫的操作:
func (msi *MemberServiceImpl) SendCode(phone string) string {
code := fmt.Sprintf("%06v", rand.New(rand.NewSource(time.Now().UnixNano())).Int31n(1000000))
...
dao := impl.NewMemberDao()
smsCode := model.SmsCode{Phone: phone, Code: code, BizId: response.BizId, CreateTime: time.Now().Unix()}
if result := dao.InsertCode(smsCode); result > 0 {
return code
}
return ""
}