
اگر شما هم یک سایت فروشگاهی، سرویس آنلاین یا اپلیکیشن دارید، حتماً با این چالش روبرو شدید:
چطور مطمئن بشم شماره موبایل کاربر واقعاً متعلق به خودشه؟
چطور بدون پیچیدگی زیاد، امنیت ثبتنام رو بالا ببرم؟
در سال ۱۴۰۴، احراز هویت دو مرحلهای (OTP) دیگه یک آپشن لوکس نیست. کاربران ایرانی بهشدت نسبت به امنیت حساس شدن و اگر سایت شما نتونه کد تایید بفرسته، احتمالاً رقیبتون رو انتخاب میکنن.
اما مشکل اینجاست: خیلی از پنلهای پیامک یا مستندات ضعیفی دارن، یا پیادهسازیشون زمانبره، یا هزینههای پنهان دارن.
در این مقاله، قراره در کمتر از ۵ دقیقه و با حدود ۳۰ خط کد، یک سیستم OTP کامل و امن به پروژه Laravel شما اضافه کنیم. بدون نیاز به پکیج اضافی، بدون پیچیدگی.
چیزی که در پایان این مقاله دارید:
✅ یک کنترلر کامل برای ارسال و بررسی کد تایید
✅ کد آماده برای کپیپیست در پروژه
✅ لینک دانلود پروژه کامل از گیتهاب
✅ پیامک رایگان برای تست
بریم شروع کنیم! 👇
قبل از شروع، مطمئن شو این موارد رو داری:
Laravel 8 یا بالاتر
اکانت PromoSMS
API Token - از پنل کاربری قابل دریافته (رایگان)
آشنایی مقدماتی با لاراول
💡 نکته: اگر هنوز اکانت نداری، همین الان ثبتنام کن. پیامک رایگان برای تست بهت هدیه میدیم.
اولین قدم، ساخت یک کنترلر برای مدیریت ارسال و بررسی کد تاییده.
در ترمینال پروژهت این دستور رو اجرا کن:
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 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
حالا وقتشه که ببینیم کد واقعاً کار میکنه!
درخواست ارسال 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 در کامنتها بنویس
موفق باشید! 💙
#لاراول #OTP #احراز_هویت #برنامه_نویسی #PromoSMS #امنیت_وب #استارتاپ #پیامک