مقالات

خانه صفحات مقالات
چگونه در ۵ دقیقه احراز هویت دو مرحله‌ای (OTP) را به Laravel اضافه کنیم؟

چگونه در ۵ دقیقه احراز هویت دو مرحله‌ای (OTP) را به Laravel اضافه کنیم؟

چرا OTP دیگه یک انتخاب نیست، یک ضرورته؟ 🔐چرا OTP دیگه یک انتخاب نیست، یک ضرورته؟ 🔐اگر شما هم یک سایت فروشگاهی، سرویس آنلاین یا اپلیکیشن دارید، حتماً با این چالش روبرو شدید:چطور مطمئن بشم شماره موبایل کاربر واقعاً متعلق به خودشه؟چطور بدون پیچیدگی زیاد، امنیت ثبت‌نام رو بالا ببرم؟در سال ۱۴۰۴، احراز هویت دو مرحله‌ای (OTP) دیگه یک آپشن لوکس نیست. کاربران ایرانی به‌شدت نسبت به امنیت حساس شدن و اگر سایت شما نتونه کد تایید بفرسته، احتمالاً رقیبتون رو انتخاب می‌کنن.اما مشکل اینجاست: خیلی از پنل‌های پیامک یا مستندات ضعیفی دارن، یا پیاده‌سازی‌شون زمان‌بره، یا هزینه‌های پنهان دارن.در این مقاله، قراره در کمتر از ۵ دقیقه و با حدود ۳۰ خط کد، یک سیستم OTP کامل و امن به پروژه Laravel شما اضافه کنیم. بدون نیاز به پکیج اضافی، بدون پیچیدگی.چیزی که در پایان این مقاله دارید:✅ یک کنترلر کامل برای ارسال و بررسی کد تایید✅ کد آماده برای کپی‌پیست در پروژه✅ لینک دانلود پروژه کامل از گیت‌هاب✅ پیامک رایگان برای تستبریم شروع کنیم! 👇چه چیزهایی نیاز داریم؟ 📋قبل از شروع، مطمئن شو این موارد رو داری:Laravel 8 یا بالاتراکانت PromoSMSAPI Token - از پنل کاربری قابل دریافت‌ه (رایگان)آشنایی مقدماتی با لاراول💡 نکته: اگر هنوز اکانت نداری، همین الان ثبت‌نام کن. پیامک رایگان برای تست بهت هدیه میدیم.ساخت کنترلر OTP 🎮اولین قدم، ساخت یک کنترلر برای مدیریت ارسال و بررسی کد تاییده.در ترمینال پروژه‌ت این دستور رو اجرا کن:php artisan make:controller OtpControllerحالا فایل app/Http/Controllers/OtpController.php رو باز کن و این کدها رو اضافه کن:<?php namespace App\Http\Controllers; use Illuminate\Http\Client\ConnectionException; use Illuminate\Http\Request; use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Log; class OtpController extends Controller { /** * ارسال کد تایید به شماره موبایل * @throws ConnectionException */ public function send(Request $request) { // اعتبارسنجی شماره موبایل $request->validate([ 'phone' => ['required', 'size:11', 'regex:/^09[0-9]{9}$/'] ]); $phone = $request->phone; // تولید کد ۵ رقمی تصادفی $code = str_pad(rand(1, 99999), 5, 0, STR_PAD_LEFT); // ذخیره کد در کش به مدت ۲ دقیقه Cache::put('otp_' . $phone, $code, 120); // ارسال پیامک با PromoSMS $response = Http::withToken(config('services.promosms.token')) ->withHeaders([ 'Accept' => 'application/json', ]) ->post('https://promosms.ir/api/send/pattern', [ 'number' => $phone, 'data' => [ 'data1' => $code, ], 'pattern_code' => config('services.promosms.patterns.login') ]); // لاگ‌گیری برای دیباگ Log::info("OTP sent to {$phone}", [ 'status' => $response->successful(), 'code' => $response->status(), 'report_id' => $response->json()['info']['report_id'], ]); return response()->json([ 'success' => $response->successful(), 'message' => $response->successful() ? 'کد تایید ارسال شد' : 'خطا در ارسال پیامک' ]); } /** * بررسی کد تایید واردشده توسط کاربر */ public function verify(Request $request) { $request->validate([ 'phone' => 'required|size:11', 'code' => 'required|size:5' ]); $phone = $request->phone; $code = $request->code; // دریافت کد ذخیره‌شده از کش $storedCode = Cache::get('otp_' . $phone); if (!$storedCode) { return response()->json([ 'success' => false, 'message' => 'کد تایید منقضی شده یا وجود ندارد' ], 400); } // بررسی صحت کد if ($storedCode != $code) { return response()->json([ 'success' => false, 'message' => 'کد تایید اشتباه است' ], 400); } // حذف کد از کش پس از موفقیت Cache::forget('otp_' . $phone); return response()->json([ 'success' => true, 'message' => 'تایید هویت با موفقیت انجام شد' ]); } }تعریف روت‌ها 🛣️حالا باید روت‌های API رو تعریف کنیم. فایل routes/api.php رو باز کن:// ارسال کد تایید (با محدودیت 1 درخواست در 2دقیقه) Route::post('/otp/send', [OtpController::class, 'send']) ->middleware('throttle:1,2'); // بررسی کد تایید Route::post('/otp/verify', [OtpController::class, 'verify']);⚠️ نکته امنیتی حیاتی:میدلور throttle:1,2 یعنی هر کاربر حداکثر می‌تونه ۱ درخواست در ۲دقیقه بفرسته. این برای جلوگیری از اسپم و سوءاستفاده ضروریه.تنظیمات API Key ⚙️برای اینکه کد کار کنه، باید API Token و Sender رو به پروژه اضافه کنی.فایل config/services.php رو باز کن و این بخش رو اضافه کن'promosms' => [ 'token' => env('PROMOSMS_API_TOKEN'), 'patterns' => [ 'login' => env('PROMOSMS_PATTERN_CODE_LOGIN') ], ],حالا در فایل .env این مقادیر رو اضافه کن:#-------Custom Env------ PROMOSMS_API_TOKEN=your_api_token_here PROMOSMS_PATTERN_CODE_LOGIN=your_pattern_codeتست با Postman 🧪حالا وقتشه که ببینیم کد واقعاً کار می‌کنه!درخواست ارسال OTP: (فقط کافیه کد زیر رو توی postman وارد کنید تا تنظیمات به صورت خودکار انجام بشه)curl --location 'http://127.0.0.1:8000/api/otp/send' \ --header 'Content-Type: application/json' \ --data '{ "phone": "09111111111" }'خروجی کد بالا باید بشه{ "success": true, "message": "کد تایید ارسال شد" }درخواست بررسی OTP:curl --location 'http://127.0.0.1:8000/api/otp/verify' \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --data '{ "phone":"09111111111", "code":"80910" }'خروجی کد بالا باید بشه{ "success": true, "message": "تایید هویت با موفقیت انجام شد" }⚠️ نکات امنیتی که باید رعایت کنیمحدودیت تعداد درخواست (Rate Limiting)همون‌طور که دیدید، از میدلور throttle استفاده کردیم. این جلوگیری می‌کنه از:اسپم شدن شماره کاربرانهزینه اضافی برای توحملات Brute Forceاعتبار زمانی کد (Expiration)کد ما فقط ۲ دقیقه اعتبار داره. بعد از این زمان، کش منقضی میشه و کاربر باید دوباره درخواست بده.عدم نمایش خطای دقیقدر پاسخ خطا، هیچ‌وقت نگو «این شماره ثبت‌نام نشده» یا «کد اشتباهه، ۲ بار دیگه شانس داری». این اطلاعات به هکرها کمک می‌کنه.لاگ‌گیری تلاش‌های ناموفقبرای تشخیص حملات، حتماً تلاش‌های ناموفق رو لاگ کنif ($storedCode != $code) { Log::warning("Failed OTP attempt for {$phone}"); // ... }🎁 هدیه ویژه: پروژه آماده گیت‌هابمی‌دونم که بعضی وقت‌ها کپی‌پیست کردن کد از روی مقاله سخته. برای همین، کل این پروژه رو به‌صورت آماده در گیت‌هاب گذاشتم.# 1. کلون کردن پروژه git clone https://github.com/PromoSmsIR/promosms-laravel-otp-example.git # 2. نصب وابستگی‌ها cd promosms-laravel-otp-example composer install # 3. کپی فایل محیطی cp .env.example .env php artisan key:generate # 4. تنظیم API Key در فایل .env #-------Custom Env------ PROMOSMS_API_TOKEN=your_api_token_here PROMOSMS_PATTERN_CODE_LOGIN=your_pattern_code # 5. اجرای سرور php artisan serveدر این ریپو پیدا می‌کنی:✅ کد کامل کنترلر و روت‌ها✅ فایل .env.example آماده✅ کلکشن Postman برای تست سریع✅ راهنمای فارسی در README🎯 حالا با این چیکار می‌تونم بکنم؟ثبت‌نام کاربران (تایید شماره موبایل هنگام ثبت‌نام)ورود دو مرحله‌ای (افزایش امنیت حساب‌های کاربری)تایید تراکنش (ارسال کد برای پرداخت‌های حساس)بازیابی رمز (ارسال کد برای ریست پسورد)❓ سوالی داری؟اگر در حین پیاده‌سازی به مشکلی خوردی، یا ایده‌ای برای بهبود کد داری، حتماً در کامنت‌ها بنویس. شخصاً جواب میدم و اگر باگی پیدا کردی، خوشحال می‌شم گزارش بدی تا ریپو رو آپدیت کنم.اگر این مقاله برات مفید بود:👍 بوک‌مارک کن که گمش نکنی🔄 برای هم‌تیمی‌هات بفرست💬 تجربه‌ت رو درباره OTP در کامنت‌ها بنویسموفق باشید! 💙لینک های مفیدثبت‌نام و تست رایگانآدرس مخزن گیت‌هابچگونه یک سرویس پیامک انبوه را با Laravel ساختیم؟ (از ایده تا اجرا)#لاراول #OTP #احراز_هویت #برنامه_نویسی #PromoSMS #امنیت_وب #استارتاپ #پیامک

چگونه یک سرویس پیامک انبوه را با Laravel ساختیم؟ (از ایده تا اجرا)

چگونه یک سرویس پیامک انبوه را با Laravel ساختیم؟ (از ایده تا اجرا)

سلام دوباره، با یک داستان جدید 👋پرومو اس‌ام‌اسسلام به همه دوستان قدیمی ویرگول! رضا هستم، همون توسعه‌دهنده‌ای که چند سال پیش درباره Laravel و API می‌نوشت.توی این چند سال، از کدنویسی صرف فاصله گرفتم و وارد دنیای چالش‌برانگیز «ساخت محصول» شدم. امروز می‌خوام داستان ساخت PromoSMS رو براتون تعریف کنم؛ سرویسی که از یک نیاز شخصی شروع شد و حالا داره به کسب‌وکارهای ایرانی کمک می‌کنه بهتر با مشتریانشون ارتباط بگیرن.اگر شما هم:- توسعه‌دهنده‌اید و می‌خواید بدونید پشت صحنه یک سرویس SaaS ایرانی چه می‌گذره،- یا صاحب کسب‌وکارید و می‌خواید بدونید چطور می‌تونید با پیامک فروش‌تون رو افزایش بدید،این مقاله برای شماست. بریم شروع کنیم! 👇چرا اصلاً سراغ ساخت پنل پیامک رفتم؟ 🤔همه چیز از یک مشکل شخصی شروع شد.وقتی داشتم روی یک پروژه فروشگاهی کار می‌کردم، نیاز داشتم که به مشتریانم پیامک تأیید سفارش بفرستم. رفتم سراغ پنل‌های موجود، اما با چند چالش روبرو شدم:1. مستندات فنی ضعیف: وب‌سرویس‌ها یا داکیومنت نداشتن، یا مثال‌هاشون قدیمی بود.2. پیچیدگی برای توسعه‌دهنده: برای یک کار ساده مثل ارسال OTP، باید از ده تا منو رد می‌شدم!3. عدم شفافیت قیمت: بعضی پنل‌ها هزینه‌های پنهان داشتن که تازه بعد از شارژ معلوم می‌شد.با خودم گفتم: «من که Full-Stack کار می‌کنم، چرا یک سرویس ساده‌تر، شفاف‌تر و دولوپر-فرندلی نسازم؟»و این‌طور شد که PromoSMS متولد شد.چالش‌های فنی ساخت یک سرویس پیامک با Laravel 💻اینجا می‌خوام کمی فنی‌تر بشم (بخش مورد علاقه دولوپرها!). ساختن یک پنل پیامک فقط «ارسال درخواست HTTP به اپراتور» نیست. چند تا چالش جدی وجود داشت:🔹 مدیریت صف‌ها (Queue) برای ارسال انبوهوقتی یک کاربر می‌خواد ۱۰,۰۰۰ پیامک تبلیغاتی بفرسته، نمی‌تونی همون لحظه همه رو ارسال کنی. سرور کرش می‌کنه!راه‌حل من: استفاده از Laravel Queue + Redis// مثال ساده: ارسال پیامک در پس‌زمینه SendSmsJob::dispatch($phoneNumber, $message) ->onQueue('sms') ->delay(now()->addSeconds(5));این‌طوری کاربر سریع فیدبک می‌گیره و ارسال واقعی در پس‌زمینه انجام میشه.🔹 یکپارچه‌سازی با چندین اپراتورهر اپراتور پیامک در ایران API متفاوتی داره (REST، SOAP، حتی XML!).راه‌حل: طراحی یک Interface واحد و پیاده‌سازی Adapter برای هر اپراتور:interface SmsProviderInterface { public function send(string $to, string $message): bool; } class MedianaAdapter implements SmsProviderInterface { ... } class KavenegarAdapter implements SmsProviderInterface { ... }این معماری به من اجازه میده بدون تغییر کد اصلی، اپراتور جدید اضافه کنم یا اگر یکی دان‌شد، خودکار سوئیچ کنم به بعدی.🔹 مقیاس‌پذیری و مانیتورینگوقتی تعداد کاربران زیاد شد، دیگه نمی‌تونستم با dd() دیباگ کنم! 😅ابزارهایی که نجاتم دادن:Laravel Telescope برای دیباگ درخواست‌هاSentry برای ردیابی خطاهاLaravel Horizon برای مانیتور کردن Queueها💡درس فنی: همیشه از روز اول لاگ‌گیری و مانیتورینگ رو جدی بگیر. وقتی مشکل پیش بیاد، وقت دیباگ ندارید!درس‌های بیزینسی که کدنویسی به من یاد نداد 📈اینجا می‌خوام از دنیای کد بیام بیرون و درباره چیزی بگم که برای صاحبان کسب‌وکار جالب‌تره.وقتی PromoSMS رو ساختم، فکر می‌کردم «اگر محصول فنی‌ام خوب باشه، مشتریان خودشون میان». اما اشتباه می‌کردم!🔸 درس ۱: مشتری «فیچر» نمی‌خره، «راه‌حل مشکل» می‌خرهیک صاحب فروشگاه اینستاگرامی نمی‌خواد بدونه من از Redis استفاده کردم یا نه. اون می‌خواد بدونه:«آیا می‌تونم وقتی سفارش جدید اومد، خودکار به مشتری پیامک بزنم تا اعتمادش جلب بشه؟»پس توی پنل، فیچرها رو با زبان «سود کسب‌وکار» توضیح دادم، نه زبان فنی.🔸 درس ۲: پشتیبانی سریع = وفاداری مشتریتوی ایران، خیلی از پنل‌های بزرگ پشتیبانی‌شون ساعت‌ها طول می‌کشه. من تصمیم گرفتم:پاسخ به تیکت‌ها در کمتر از ۲ ساعت کاریپاسخ مستقیم من (به‌عنوان سازنده) به سوالات فنی در لینکدین و توییترنتیجه؟ کاربران قدیمی دارن دوستانشون رو معرفی می‌کنن. این یعنی بازاریابی رایگان!🔸 درس ۳: شفافیت، اعتماد می‌سازهتوی صفحه تعرفه‌ها، دقیقاً نوشتم هر پیامک چقدر هزینه داره. بدون «هزینه پنهان»، بدون «کارمزد نامرئی».شاید فکر کنید اینطوری سودم کمتر میشه، اما برعکس: وقتی کاربر اعتماد کنه، بیشتر شارژ می‌کنه و طولانی‌تر می‌مونه.حالا نوبت شماست 👇اگر شما هم توسعه‌دهنده‌اید و می‌خواید این سرویس رو تست کنید:📚 مستندات فنی🎁 پیامک رایگان برای شروعاگر صاحب کسب‌وکارید و می‌خواید بدونید چطور با پیامک فروش‌تون رو افزایش بدید من رو دنبال کنیدو در پایان... ✨ساختن یک محصول، فقط کدنویسی نیست. ترکیبی‌ه از:تخصص فنی ✅درک نیاز مشتری ✅صبر و یادگیری مستمر ✅اگر شما هم ایده‌ای دارید که می‌خواید تبدیلش کنید به محصول، یا سوالی درباره پیاده‌سازی فنی PromoSMS دارید، توی کامنت‌ها بنویسید. قول میدم شخصاً جواب بدم. 👇ممنون که تا اینجا خوندید. اگر این مقاله براتون مفید بود، با به‌اشتراک‌گذاری‌اش به من کمک کنید تا داستان‌های بیشتری از پشت صحنه استارتاپ‌های ایرانی براتون بنویسم. 💙#لاراول #استارتاپ #پیامک_مارکتینگ #توسعه_فردی #PromoSMS #برنامه_نویسی #کسب_و_کار_اینترنتی