组织一直在寻找创新的方法来解决平台上的威胁和脆弱性。他们不断投资人力资源和技术,以帮助建立和运输安全的应用程序。两因素身份验证,身份验证器应用程序和生物识别技术等是组织采用的一些创新方法来确保其平台安全。
在这篇文章中,我们将学习如何使用GO和Twilio的验证服务来构建用户使用电话号码来验证用户的API。对于这篇文章,我们将使用杜松子酒来构建我们的API。但是,同样的方法也适用于任何基于GO的框架。
先决条件
为了完全掌握本教程中提出的概念,适用以下要求:
- 对GO的基本理解
- GO安装(上面版本1.18)
- 一个Twilio帐户;试用帐户的signup是完全免费的。
入门
要开始,我们需要导航到所需的目录并在我们的终端中运行下面的命令:
mkdir go-sms-verification && cd go-sms-verification
此命令创建一个go-sms-verification
文件夹并导航到项目目录。
接下来,我们需要通过运行以下命令来初始化一个GO模块来管理项目依赖项:
go mod init go-sms-verification
此命令将创建一个用于跟踪项目依赖项的go.mod
文件。
我们继续使用:
安装所需的依赖项
go get github.com/gin-gonic/gin github.com/twilio/twilio-go github.com/joho/godotenv github.com/go-playground/validator/v10
github.com/gin-gonic/gin
是用于构建Web应用程序的框架。
github.com/twilio/twilio-go
是用于与Twilio通信的GO包。
github.com/joho/godotenv
是用于管理环境变量的库。
github.com/go-playground/validator/v10
是用于验证结构和字段的库。
构建我们的应用
必须拥有一个良好的项目结构,因为它使项目可以维护,并使我们和其他人更容易阅读我们的代码库。
为此,我们需要在我们的项目目录中创建一个api
,cmd
和data
文件夹。
api
用于构建我们的API相关文件
cmd
用于构建我们的应用程序入口点
data
用于构建我们的应用程序数据
设置Twilio
要在API中启用OTP验证,我们需要登录我们的Twilio Console,以获取我们的帐户SID 和 auth Token 。我们需要在需要配置和构建API时将这些参数保持方便。
创建验证服务
Twilio船提供安全且可靠的服务,可通过短信,语音和电子邮件无缝验证用户。在我们的情况下,我们将使用SMS选项通过电话号码验证用户。为此,请导航到探索产品选项卡,滚动到帐户安全部分,然后单击验证按钮。
导航到 services 选项卡,单击创建新按钮,输入 sms-service 作为友好名称,请切换 SMS 选项,创建。
创建后,我们需要复制服务sid。在构建我们的API时也将派上用场。
启用 g eagraphical p emmission
地理许可是Twilio控制其服务使用的机制。它提供了一种工具,用于启用和禁用从Twilio帐户接收语音通话和SMS消息的国家。
要启用SMS,我们需要在搜索栏中搜索SMS地理权限,请单击 SMS地理权限结果,然后检查 SMS的国家提供者运营。
在GO中创建OTP验证API
完成配置后,我们可以按照步骤开始构建API。
添加环境变量
接下来,我们需要在根目录中创建一个.env
文件,然后添加下面的摘要:
TWILIO_ACCOUNT_SID=<ACCOUNT SID>
TWILIO_AUTHTOKEN=<AUTH TOKEN>
TWILIO_SERVICES_ID=<SERVICE ID>
如前所述,我们可以从Twilio控制台和服务设置中获得所需的凭据。
最后,我们需要创建用于将环境变量加载到应用程序的助手功能。为此,我们需要在api
文件夹中创建一个config.go
文件,然后添加下面的摘要:
package api
import (
"log"
"os"
"github.com/joho/godotenv"
)
func envACCOUNTSID() string {
println(godotenv.Unmarshal(".env"))
err := godotenv.Load(".env")
if err != nil {
log.Fatalln(err)
log.Fatal("Error loading .env file")
}
return os.Getenv("TWILIO_ACCOUNT_SID")
}
func envAUTHTOKEN() string {
err := godotenv.Load()
if err != nil {
log.Fatal("Error loading .env file")
}
return os.Getenv("TWILIO_AUTHTOKEN")
}
func envSERVICESID() string {
err := godotenv.Load()
if err != nil {
log.Fatal("Error loading .env file")
}
return os.Getenv("TWILIO_SERVICES_ID")
}
上面的摘要执行以下操作:
- 导入所需的依赖项
- 创建一个
envACCOUNTSID
,envAUTHTOKEN
和envSERVICESID
功能,该功能检查环境变量是否正确加载并返回环境变量。
创建API模型
接下来,我们需要创建模型来表示我们的应用程序数据。为此,我们需要导航到data
文件夹,在此文件夹中,创建一个model.go
文件,然后添加下面的摘要:
package data
type OTPData struct {
PhoneNumber string `json:"phoneNumber,omitempty" validate:"required"`
}
type VerifyData struct {
User *OTPData `json:"user,omitempty" validate:"required"`
Code string `json:"code,omitempty" validate:"required"`
}
创建API路线,助手,服务和处理程序
使用用于发送和验证OTP的模型完全设置,我们需要导航到api
文件夹并执行以下操作:
首先,我们需要创建一个用于配置API路由的route.go
文件,并在下面添加摘要:
package api
import "github.com/gin-gonic/gin"
type Config struct {
Router *gin.Engine
}
func (app *Config) Routes() {
//routes will come here
}
上面的摘要执行以下操作:
- 导入所需的依赖项
- 使用
Router
属性创建一个Config
结构,以配置应用程序方法 - 创建一个
Routes
函数,该函数将Config
struct作为指针
其次,我们需要创建一个helper.go
文件,然后添加下面的摘要:
package api
import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
)
type jsonResponse struct {
Status int `json:"status"`
Message string `json:"message"`
Data any `json:"data"`
}
var validate = validator.New()
func (app *Config) validateBody(c *gin.Context, data any) error {
//validate the request body
if err := c.BindJSON(&data); err != nil {
return err
}
//use the validator library to validate required fields
if err := validate.Struct(&data); err != nil {
return err
}
return nil
}
func (app *Config) writeJSON(c *gin.Context, status int, data any) {
c.JSON(status, jsonResponse{Status: status, Message: "success", Data: data})
}
func (app *Config) errorJSON(c *gin.Context, err error, status ...int) {
statusCode := http.StatusBadRequest
if len(status) > 0 {
statusCode = status[0]
}
c.JSON(statusCode, jsonResponse{Status: statusCode, Message: err.Error()})
}
上面的摘要执行以下操作:
- 导入所需的依赖项
- 创建一个
jsonResponse
struct和validate
变量来描述API响应并验证API字段 - 创建一个
validateBody
函数,该函数将Config
struct作为指针作为指针并返回error
。在函数内部,我们以正确格式验证该请求data
,并使用验证库验证并检查所需字段 - 创建一个
writeJSON
函数,该函数将Config
struct作为指针作为指针,并使用jsonResponse
struct在没有错误的情况下构造API响应 - 创建一个
errorJSON
函数,该函数将Config
struct作为指针作为指针,并在存在错误时使用jsonResponse
struct构造API响应
第三,我们需要创建一个用于抽象应用程序逻辑的service.go
文件,并在下面添加摘要:
package api
import (
"github.com/twilio/twilio-go"
twilioApi "github.com/twilio/twilio-go/rest/verify/v2"
)
var client *twilio.RestClient = twilio.NewRestClientWithParams(twilio.ClientParams{
Username: envACCOUNTSID(),
Password: envAUTHTOKEN(),
})
func (app *Config) twilioSendOTP(phoneNumber string) (string, error) {
params := &twilioApi.CreateVerificationParams{}
params.SetTo(phoneNumber)
params.SetChannel("sms")
resp, err := client.VerifyV2.CreateVerification(envSERVICESID(), params)
if err != nil {
return "", err
}
return *resp.Sid, nil
}
func (app *Config) twilioVerifyOTP(phoneNumber string, code string) error {
params := &twilioApi.CreateVerificationCheckParams{}
params.SetTo(phoneNumber)
params.SetCode(code)
resp, err := client.VerifyV2.CreateVerificationCheck(envSERVICESID(), params)
if err != nil {
return err
} else if *resp.Status == "approved" {
return nil
}
return nil
}
上面的摘要执行以下操作:
- 导入所需的依赖项
- 创建一个
client
变量,以使用帐户SID 和 auth Token 配置Twilio客户端 - 创建一个接受
phoneNumber
的twilioSendOTP
函数,将Config
struct作为指针接收,并返回string
或error
。在函数内部,我们通过添加phoneNumber
并设置将OTP作为sms
的频道创建了一个params
变量。最后,我们使用client
变量通过使用服务sid 和params
创建验证,然后返回适当的响应 - 创建一个接受
phoneNumber
和code
的twilioVerifyOTP
函数,将Config
struct作为指针接收,并返回error
。在函数内部,我们通过添加phoneNumber
和code
创建了一个params
变量。最后,我们使用client
变量通过使用服务sid 和params
来检查OTP的真实性,然后返回适当的响应
第四,我们需要创建一个handler.go
文件,以修改传入请求并添加下面的摘要:
package api
import (
"context"
"go-sms-verification/data"
"net/http"
"time"
"github.com/gin-gonic/gin"
)
const appTimeout = time.Second * 10
func (app *Config) sendSMS() gin.HandlerFunc {
return func(c *gin.Context) {
_, cancel := context.WithTimeout(context.Background(), appTimeout)
var payload data.OTPData
defer cancel()
app.validateBody(c, &payload)
newData := data.OTPData{
PhoneNumber: payload.PhoneNumber,
}
_, err := app.twilioSendOTP(newData.PhoneNumber)
if err != nil {
app.errorJSON(c, err)
return
}
app.writeJSON(c, http.StatusAccepted, "OTP sent successfully")
}
}
func (app *Config) verifySMS() gin.HandlerFunc {
return func(c *gin.Context) {
_, cancel := context.WithTimeout(context.Background(), appTimeout)
var payload data.VerifyData
defer cancel()
app.validateBody(c, &payload)
newData := data.VerifyData{
User: payload.User,
Code: payload.Code,
}
err := app.twilioVerifyOTP(newData.User.PhoneNumber, newData.Code)
if err != nil {
app.errorJSON(c, err)
return
}
app.writeJSON(c, http.StatusAccepted, "OTP verified successfully")
}
}
上面的摘要执行以下操作:
- 导入所需的依赖项
- 创建一个
appTimeout
变量来设置请求超时 - 创建一个
sendSMS
函数,该函数返回杜松子酒处理程序,并将Config
结构作为指针接收。在返回的处理程序内部,我们定义了API超时,使用了助手功能,并较早创建的服务来验证请求主体并发送OTP - 创建一个
verifySMS
函数,该功能返回杜松子酒处理程序,并将Config
结构作为指针接收。在返回的处理程序内部,我们定义了API超时,使用了助手功能,并较早创建的服务来验证请求主体和OTP
最后,我们需要更新routes.go
文件API路由和相应的处理程序
package api
import "github.com/gin-gonic/gin"
type Config struct {
Router *gin.Engine
}
//modify below
func (app *Config) Routes() {
app.Router.POST("/otp", app.sendSMS())
app.Router.POST("/verifyOTP", app.verifySMS())
}
将它们全部放在一起
通过完全设置API,我们需要创建应用程序输入点。为此,我们需要导航到cmd
文件夹,在此文件夹中,创建一个main.go
文件,然后添加下面的摘要:
package main
import (
"go-sms-verification/api"
"github.com/gin-gonic/gin"
)
func main() {
router := gin.Default()
//initialize config
app := api.Config{Router: router}
//routes
app.Routes()
router.Run(":80")
}
上面的摘要执行以下操作:
- 导入所需的依赖项
- 使用
Default
配置创建杜松子路由器 - 通过传递
Router
初始化Config
结构 - 添加路线并在端口
:80
上运行应用程序
完成此操作,我们可以使用以下命令启动开发服务器:
go run cmd/main.go
我们还可以通过导航到Twilio
上的 logs 选项卡来验证消息日志结论
这篇文章讨论了如何创建使用GO和Twilio的验证服务来检查和验证用户的API。除了基于SMS的验证之外,Twilio还会发货多个服务以将身份验证无缝整合到新的或现有的代码库中。
这些资源可能会有所帮助: