本期詳細介紹了透過 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中文網其他相關文章!