この回では、Twilio を介した OTP 配信の実装、ゴルーチンを使用した非同期的な 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 送信はサーバーのパフォーマンスを妨げます。 この解決策には、ゴルーチンを利用して 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
を使用してゴルーチンを管理し、シャットダウンする前に完了を保証します。
ユーザー トークンを保存するために新しいデータベース テーブルが作成されます:
<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>
これにより、トークンの生成がサインアップ フローに統合されます。
3 つのミドルウェア層: recoverPanic
、authenticate
、および requireAuthenticatedUser
により、セキュリティとリクエスト処理が強化されます。 これらは、原文に示されているように実装され、ルートに適用されます。 コンテキスト管理関数 (contextSetUser
および contextGetUser
) は、リクエスト コンテキスト内でユーザー データを保存および取得するために使用されます。
サーバー構成にはこれらのミドルウェアが統合されており、例では requireAuthenticatedUser
を使用してルートを保護する方法を示しています。 将来の機能強化には、ファイルのアップロード、正常なシャットダウン、メトリクスの統合が含まれます。 完全なコードは GitHub で入手できます。
以上がGo を使用して OTP ベースの認証サーバーを構築する: パート 3の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。