本期详细介绍了通过 Twilio 实现 OTP 传送、使用 goroutine 优化 OTP 异步发送,以及建立强大的基于令牌的身份验证系统。
使用 Twilio 消息 API 发送 OTP 的核心功能如下所示:
<code class="language-go">func (app *application) sendOTPViaTwilio(otp, phoneNumber string) error { client := twilio.NewRestClientWithParams(twilio.ClientParams{ Username: os.Getenv("TWILIO_SID"), Password: os.Getenv("TWILIO_API_KEY"), }) params := &api.CreateMessageParams{} params.SetBody(fmt.Sprintf( "Thank you for choosing Cheershare! Your one-time password is %v.", otp, )) params.SetFrom(os.Getenv("TWILIO_PHONE_NUMBER")) params.SetTo(fmt.Sprintf("+91%v", phoneNumber)) const maxRetries = 3 var lastErr error for attempt := 1; attempt <= maxRetries; attempt++ { resp, err := client.SendSms(params) if err == nil { app.logger.Printf("Message SID: %s", resp.Sid) return nil } lastErr = err time.Sleep(time.Duration(attempt) * 100 * time.Millisecond) } return fmt.Errorf("failed to send OTP after %d retries: %w", maxRetries, lastErr) }</code>
该函数利用 Twilio 的 Go SDK 发送消息。 from
号码是预先配置的 Twilio 号码。 包含重试机制以确保可靠性。
顺序 OTP 发送会影响服务器性能。 该解决方案涉及利用 goroutine 来同时处理 OTP 传递。 application
结构已更新:
<code class="language-go">type application struct { wg sync.WaitGroup config config models data.Models logger *log.Logger cache *redis.Client }</code>
辅助函数有助于后台任务执行:
<code class="language-go">func (app *application) background(fn func()) { app.wg.Add(1) go func() { defer app.wg.Done() defer func() { if err := recover(); err != nil { app.logger.Printf("Error in background function: %v\n", err) } }() fn() }() }</code>
这使用 sync.WaitGroup
来管理 goroutine,确保在关闭之前完成。
创建一个新的数据库表来存储用户令牌:
<code class="language-sql">-- 000002_create-token.up.sql CREATE TABLE IF NOT EXISTS tokens ( hash bytea PRIMARY KEY, user_id bigint NOT NULL REFERENCES users ON DELETE CASCADE, expiry timestamp(0) with time zone NOT NULL, scope text NOT NULL ); -- 000002_create-token.down.sql DROP TABLE IF EXISTS tokens;</code>
该表存储哈希令牌、用户 ID、到期时间和令牌范围。 数据库迁移是使用migrate
.
data/models.go
文件包含用于令牌生成、插入和检索的函数:
<code class="language-go">// ... (other imports) ... package data // ... (other code) ... func generateToken(userId int64, ttl time.Duration, scope string) (*Token, error) { // ... (token generation logic) ... } func (m TokenModel) Insert(token *Token) error { // ... (database insertion logic) ... } func (m TokenModel) DeleteAllForUser(scope string, userID int64) error { // ... (database deletion logic) ... } func (m TokenModel) New(userId int64, ttl time.Duration, scope string) (*Token, error) { // ... (token creation and insertion logic) ... }</code>
此代码处理令牌创建、散列和数据库交互。 New
函数创建并存储新令牌。
cmd/api/user.go
文件的注册处理程序已修改为在成功 OTP 验证后颁发令牌:
<code class="language-go">// ... (other functions) ... func (app *application) handleUserSignupAndVerification(w http.ResponseWriter, r *http.Request) { // ... (input parsing and validation) ... // ... (OTP generation and sending logic) ... // ... (OTP verification logic) ... // ... (user creation or retrieval) ... token, err := app.generateTokenForUser(user.ID) if err != nil { // ... (error handling) ... } // ... (success response with token) ... }</code>
这将令牌生成集成到注册流程中。
三个中间件层增强了安全性和请求处理:recoverPanic
、authenticate
和 requireAuthenticatedUser
。 这些已实现并应用于路由,如原文所示。 上下文管理函数(contextSetUser
和 contextGetUser
)用于在请求上下文中存储和检索用户数据。
服务器配置集成了这些中间件,示例展示了如何使用requireAuthenticatedUser
保护路由。 未来的增强功能包括文件上传、正常关闭和指标集成。 完整的代码可以在 GitHub 上找到。
以上是使用 Go 构建基于 OTP 的身份验证服务器:第 3 部分的详细内容。更多信息请关注PHP中文网其他相关文章!