Maison > développement back-end > Golang > Créer un serveur d'authentification basé sur OTP avec Go : partie 3

Créer un serveur d'authentification basé sur OTP avec Go : partie 3

DDD
Libérer: 2025-01-10 18:03:43
original
849 Les gens l'ont consulté

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

Cet article détaille la mise en œuvre de la livraison OTP via Twilio, l'optimisation de l'envoi OTP de manière asynchrone à l'aide de goroutines et l'établissement d'un système d'authentification robuste basé sur des jetons.

Envoi d'OTP avec Twilio

La fonction principale d'envoi d'OTP à l'aide de l'API de messagerie de Twilio est présentée ci-dessous :

<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>
Copier après la connexion

Cette fonction utilise le SDK Go de Twilio pour envoyer des messages. Le numéro from est un numéro Twilio préconfiguré. Un mécanisme de nouvelle tentative est inclus pour plus de fiabilité.

Envoi OTP asynchrone avec Goroutines

L'envoi OTP séquentiel entrave les performances du serveur. La solution consiste à utiliser des goroutines pour gérer simultanément la livraison d'OTP. La structure application est mise à jour :

<code class="language-go">type application struct {
    wg     sync.WaitGroup
    config config
    models data.Models
    logger *log.Logger
    cache  *redis.Client
}</code>
Copier après la connexion

Une fonction d'assistance facilite l'exécution des tâches en arrière-plan :

<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>
Copier après la connexion

Ceci utilise sync.WaitGroup pour gérer les goroutines, garantissant leur achèvement avant l'arrêt.

Tableau des jetons de base de données

Une nouvelle table de base de données est créée pour stocker les jetons utilisateur :

<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>
Copier après la connexion

Ce tableau stocke les jetons hachés, les identifiants utilisateur, les délais d'expiration et les étendues des jetons. La migration de la base de données s'effectue à l'aide de migrate.

Modèle et fonctions du jeton

Le fichier data/models.go comprend des fonctions de génération, d'insertion et de récupération de jetons :

<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>
Copier après la connexion

Ce code gère la création de jetons, le hachage et l'interaction avec la base de données. La fonction New crée et stocke de nouveaux jetons.

Mises à jour du gestionnaire d'inscription

Le gestionnaire d'inscription du fichier cmd/api/user.go est modifié pour émettre des jetons en cas de vérification OTP réussie :

<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>
Copier après la connexion

Cela intègre la génération de jetons dans le flux d'inscription.

Couches middleware

Trois couches middleware améliorent la sécurité et la gestion des requêtes : recoverPanic, authenticate et requireAuthenticatedUser. Ceux-ci sont implémentés et appliqués aux itinéraires comme indiqué dans le texte original. Les fonctions de gestion de contexte (contextSetUser et contextGetUser) sont utilisées pour stocker et récupérer les données utilisateur dans le contexte de la demande.

La configuration du serveur intègre ces middlewares, et l'exemple montre comment protéger les routes à l'aide de requireAuthenticatedUser. Les améliorations futures incluent le téléchargement de fichiers, l'arrêt progressif et l'intégration de métriques. Le code complet est disponible sur GitHub.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal