ホームページ > バックエンド開発 > Golang > Go を使用して OTP ベースの認証サーバーを構築する: パート 3

Go を使用して OTP ベースの認証サーバーを構築する: パート 3

DDD
リリース: 2025-01-10 18:03:43
オリジナル
851 人が閲覧しました

Build an OTP-Based Authentication Server with Go: Part 3

この回では、Twilio を介した OTP 配信の実装、ゴルーチンを使用した非同期的な OTP 送信の最適化、および堅牢なトークンベースの認証システムの確立について詳しく説明します。

Twilio で 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 送信はサーバーのパフォーマンスを妨げます。 この解決策には、ゴルーチンを利用して 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 つのミドルウェア層: recoverPanicauthenticate、および requireAuthenticatedUser により、セキュリティとリクエスト処理が強化されます。 これらは、原文に示されているように実装され、ルートに適用されます。 コンテキスト管理関数 (contextSetUser および contextGetUser) は、リクエスト コンテキスト内でユーザー データを保存および取得するために使用されます。

サーバー構成にはこれらのミドルウェアが統合されており、例では requireAuthenticatedUser を使用してルートを保護する方法を示しています。 将来の機能強化には、ファイルのアップロード、正常なシャットダウン、メトリクスの統合が含まれます。 完全なコードは GitHub で入手できます。

以上がGo を使用して OTP ベースの認証サーバーを構築する: パート 3の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート