Butiran ansuran ini melaksanakan penghantaran OTP melalui Twilio, mengoptimumkan penghantaran OTP secara tidak segerak menggunakan goroutin dan mewujudkan sistem pengesahan berasaskan token yang mantap.
Fungsi teras untuk menghantar OTP menggunakan API pemesejan Twilio dibentangkan di bawah:
<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>
Fungsi ini menggunakan Twilio's Go SDK untuk menghantar mesej. Nombor from
ialah nombor Twilio yang diprakonfigurasikan. Mekanisme cuba semula disertakan untuk kebolehpercayaan.
Penghantaran OTP berurutan menghalang prestasi pelayan. Penyelesaiannya melibatkan penggunaan goroutine untuk mengendalikan penghantaran OTP secara serentak. Struktur application
dikemas kini:
<code class="language-go">type application struct { wg sync.WaitGroup config config models data.Models logger *log.Logger cache *redis.Client }</code>
Fungsi pembantu memudahkan pelaksanaan tugas latar belakang:
<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>
Ini menggunakan sync.WaitGroup
untuk mengurus goroutine, memastikan siap sebelum ditutup.
Jadual pangkalan data baharu dicipta untuk menyimpan token pengguna:
<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>
Jadual ini menyimpan token cincang, ID pengguna, masa tamat tempoh dan skop token. Penghijrahan pangkalan data dilakukan menggunakan migrate
.
Fail data/models.go
termasuk fungsi untuk penjanaan, penyisipan dan pengambilan token:
<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>
Kod ini mengendalikan penciptaan token, pencincangan dan interaksi pangkalan data. Fungsi New
mencipta dan menyimpan token baharu.
Pengendali pendaftaran fail cmd/api/user.go
diubah suai untuk mengeluarkan token apabila pengesahan OTP berjaya:
<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>
Ini menyepadukan penjanaan token ke dalam aliran pendaftaran.
Tiga lapisan perisian tengah meningkatkan keselamatan dan pengendalian permintaan: recoverPanic
, authenticate
dan requireAuthenticatedUser
. Ini dilaksanakan dan digunakan pada laluan seperti yang ditunjukkan dalam teks asal. Fungsi pengurusan konteks (contextSetUser
dan contextGetUser
) digunakan untuk menyimpan dan mendapatkan semula data pengguna dalam konteks permintaan.
Konfigurasi pelayan menyepadukan perisian tengah ini dan contoh menunjukkan cara melindungi laluan menggunakan requireAuthenticatedUser
. Penambahbaikan masa hadapan termasuk memuat naik fail, penutupan anggun dan penyepaduan metrik. Kod lengkap tersedia di GitHub.
Atas ialah kandungan terperinci Bina Pelayan Pengesahan Berasaskan OTP dengan Go: Bahagian 3. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!