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.
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>
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é.
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>
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>
Ceci utilise sync.WaitGroup
pour gérer les goroutines, garantissant leur achèvement avant l'arrêt.
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>
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
.
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>
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.
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>
Cela intègre la génération de jetons dans le flux d'inscription.
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!