به محتوای اصلی

احراز هویت با شماره موبایل؛ ورود OTP پیامکی بدون کدنویسی

ورود کاربران با شماره موبایل و کد یکبار مصرف پیامکی، بدون نوشتن بک‌اند: ارسال و تأیید OTP با دو درخواست، ساخت خودکار حساب، سقف تلاش و انقضای آماده.

عاطفه امیری۶ دقیقه مطالعه
در این مطلب

برای کاربر ایرانی طبیعی‌ترین راه ورود به اپ، شماره موبایل و کد پیامکی است: رمزی نیست که فراموش شود و فرم ثبت‌نامی نیست که نیمه‌کاره رها شود. در فیکارو احراز هویت با شماره موبایل از قبل ساخته شده و کل جریان دو درخواست HTTP است: اولی کد یکبار مصرف (OTP) را پیامک می‌کند، دومی کد را تأیید می‌کند و توکن برمی‌گرداند. اگر حسابی با آن شماره وجود نداشته باشد، همان لحظه ساخته می‌شود — ثبت‌نام و ورود یک جریان‌اند. این مقاله همان دو درخواست را با کد واقعی نشان می‌دهد و می‌گوید پشت‌شان چه چیزهایی از قبل رعایت شده که در پیاده‌سازی دستی معمولاً جا می‌ماند.

ورود با کد یکبار مصرف چطور کار می‌کند؟

ورود با کد یکبار مصرف از بیرون سه قدم است: کاربر شماره‌اش را وارد می‌کند، یک کد ۶ رقمی برایش پیامک می‌شود، کد را می‌نویسد و وارد می‌شود. چیزی که ساده نیست، دوروبرِ همین سه قدم است: کد باید جایی ذخیره شود (و نه به‌صورت خام)، باید منقضی شود، تلاش‌های اشتباه باید شمرده شوند، ارسال دوباره باید سقف داشته باشد، و کدی که یک بار مصرف شد نباید دوباره کار کند.

نکته‌ای که موقع جست‌وجو گمراه‌کننده است: بیشتر نتایجِ «وب‌سرویس OTP» در واقع پنل پیامکی‌اند و فقط رساندنِ پیامک به گوشی کاربر را حل می‌کنند. تولید کد، ذخیره‌ی امن، انقضا، شمارش تلاش، ساخت حساب و صدور توکن همچنان با شماست — یعنی دقیقاً همان بخشی که خطاهای امنیتی در آن اتفاق می‌افتد. احراز هویت پیامکی کامل یعنی همه‌ی این‌ها با هم، نه فقط ارسال پیامک.

OTP یا رمز عبور؛ کدام برای اپ شما درست است؟

کد پیامکی (OTP)رمز عبور
کاربر چه چیزی به خاطر می‌سپارد؟هیچ — گوشی دستش باشد کافی استرمزی که فراموش و تکرار می‌شود
ثبت‌نامخودکار، در اولین ورودفرم جدا می‌خواهد
هزینه‌ی هر ورودیک پیامکصفر
به چه چیزی وابسته است؟آنتن و رسیدن پیامکحافظه‌ی کاربر
ریسک اصلیدسترسی دیگری به سیم‌کارترمز لورفته یا ضعیف
مناسبِاپ موبایل و کاربر عادیپنل وب و کاربر همیشگی

لازم نیست یکی را انتخاب کنید: در فیکارو هر دو روش روی یک حساب کار می‌کنند و ورود با رمز عبور و JWT هم به همین شکل آماده است. بازیابی رمز هم با همین کد پیامکی انجام می‌شود، پس جریان «رمزم را فراموش کرده‌ام» را هم جداگانه نمی‌سازید.

کجا کد پیامکی به‌تنهایی کافی نیست؟

کد پیامکی برای هر کاربردی کافی نیست — و این را کمتر جایی به فارسی می‌خوانید: ویرایش چهارم سند NIST SP 800-63B، منتشرشده در مرداد ۱۴۰۴، در بند ۳.۱.۳.۳ استفاده از شبکه‌ی تلفن برای احراز هویت — یعنی همین کد پیامکی — را رسماً «محدود» اعلام کرده، و در زمان انتشار آن سند، تنها روش محدودشده‌ی این استاندارد است. دلیلش هم مشخص است: سیم‌کارت جابه‌جا می‌شود، شماره منتقل می‌شود، و پیامک روی مسیری می‌رود که شما کنترلش نمی‌کنید.

«محدود» یعنی ممنوع نیست، یعنی باید بدانید کجا استفاده‌اش می‌کنید. برای اپ فروشگاهی، سفارش غذا، رزرو نوبت و اکثر محصولات مصرفی، ورود با کد پیامکی همچنان انتخاب درست و متعارفی است. اما اگر پشت آن پول، دارایی یا داده‌ی حساس هست، همان سند دو توصیه‌ی عملی دارد: پیش از ارسال کد به نشانه‌های خطر مثل تعویض سیم‌کارت و انتقال شماره توجه کنید، و همیشه یک روش ورود جایگزین در دسترس بگذارید — چون کاربری که آنتن ندارد، بدون آن اصلاً نمی‌تواند وارد شود. همین توصیه‌ی دوم دلیل خوبی است که رمز عبور را هم روشن نگه دارید، نه اینکه فقط روی پیامک تکیه کنید. متن کامل در سند رسمی NIST آمده است.

پیاده‌سازی دستی OTP کجا خراب می‌شود؟

فهرست خطاهایی که در کدهای دست‌نویس بارها تکرار شده:

  • ذخیره‌ی کد به‌صورت خام. هر کسی که به دیتابیس یا لاگ برسد، کد ورود همه را دارد. کد باید مثل رمز، هش شود.
  • کد بدون انقضا. کدی که دیروز پیامک شده نباید امروز کار کند.
  • نبود سقف تلاش. کد ۶ رقمی فقط یک میلیون حالت دارد؛ بدون قفل شدن بعد از چند تلاش، حدس زدنش مسئله‌ی زمان است نه امکان.
  • نبود سقف ارسال. یک حلقه‌ی ساده روی اندپوینت ارسال، هم قبض پیامک شما را نجومی می‌کند و هم اپ شما را ابزار آزارِ شماره‌های مردم.
  • کد چندبارمصرف. کدی که تأیید شد باید همان لحظه بسوزد، وگرنه شنودشدنش یعنی یک ورود دیگر.

در فیکارو این فهرست از قبل بسته شده است: کد هش‌شده نگه‌داری می‌شود، ۵ دقیقه اعتبار دارد، بعد از ۳ تلاش اشتباه قفل می‌شود و باید کد جدید گرفت، هر شماره در هر ۱۰ دقیقه حداکثر ۳ کد می‌گیرد، و کد مصرف‌شده بلافاصله باطل می‌شود.

ارسال و تأیید کد: دو درخواست، تمام

قدم اول کد را می‌فرستد و قدم دوم آن را به یک نشست تبدیل می‌کند:

POST /v1/auth/otp/send
{ "mobile": "09121234567" }
→ 204

POST /v1/auth/otp/verify
{ "mobile": "09121234567", "code": "482913" }
→ { "user": { ... }, "access_token": "eyJ...", "refresh_token": "...", "expires_at": "..." }

اگر حسابی با این شماره نباشد، در همان تأیید ساخته می‌شود. ارقام فارسی هم ورودی معتبرند — کاربری که با کیبورد فارسی «۰۹۱۲…» را می‌نویسد به دیوار نمی‌خورد. همین قاعده جای دیگری هم لازم می‌شود: جست‌وجوی فارسی در دیتابیس نشان می‌دهد ارقام و ی و ک و نیم‌فاصله چطور نتیجه‌ی جست‌وجو را خالی می‌کنند. همین جریان در جاوااسکریپت:

const base = "https://api.fikaro.ir/my-app/v1";

// قدم ۱ — ارسال کد
await fetch(`${base}/auth/otp/send`, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ mobile: "09121234567" }),
});

// قدم ۲ — کاربر کد را از پیامک می‌خواند و وارد می‌کند
const res = await fetch(`${base}/auth/otp/verify`, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ mobile: "09121234567", code }),
});
const { user, access_token, refresh_token } = await res.json();

// از این به بعد، هر درخواست از طرف همین کاربر است
await fetch(`${base}/order`, {
  headers: { Authorization: `Bearer ${access_token}` },
});

کد و شماره موبایل را در کلاینت همیشه رشته نگه دارید، نه عدد. کد «۰۴۵۶۷۱» اگر به عدد تبدیل شود صفرِ اولش می‌افتد و تأیید همیشه شکست می‌خورد — و شماره‌ی «۰۹۱۲…» هم دقیقاً همین‌طور. این خطا در فرم‌های موبایل بیشتر از هر چیز دیگری وقت می‌سوزاند.

توکن دسترسی که منقضی شد، با POST /v1/auth/refresh و همان refresh_token بدون پیامک دوباره تمدید می‌شود. نگه‌داری امن توکن هم همان قاعده‌های همیشگی را دارد: حافظه‌ی امن سیستم‌عامل در موبایل، کوکی httpOnly در وب.

فعال‌سازی و هزینه‌ی پیامک از کجا می‌آید؟

ورود با موبایل برای هر پروژه از کارت «روش‌های ورود» در پنل روشن و خاموش می‌شود و پیش‌فرضش روشن است؛ وقتی خاموش باشد، اندپوینت‌های OTP با خطای صریح otp_disabled جواب می‌دهند نه با رفتار مبهم.

ارسال پیامک داخل خود سرویس انجام می‌شود — یعنی نه پنل پیامکی جدا می‌خرید، نه قرارداد و شماره‌ی خدماتی جدا می‌گیرید، و نه کلید یک سرویس دیگر را در جایی نگه می‌دارید.

هزینه‌اش هم داخل پلن نیست و سهمیه‌ی ماهانه ندارد: بهای هر ارسال همان لحظه از کیف‌پول شما کم می‌شود و ماهی که پیامکی نفرستید، بابت پیامک چیزی نمی‌پردازید. قیمت روزِ هر پیامک در تعرفه‌ها نوشته شده. اگر موجودی کیف‌پول کفاف ندهد، کد اصلاً فرستاده نمی‌شود و اندپوینت 503 برمی‌گرداند؛ بقیه‌ی روش‌های ورود سر جایشان می‌مانند و شما همان روز اعلان می‌گیرید.

گام بعدی

مرجع کامل کلیدها و توکن‌ها در مستندات احراز هویت است. اگر اپ موبایل می‌سازید، بک‌اند فلاتر و ری‌اکت‌نیتیو همین جریان را کنار اتصال، صفحه‌بندی و آپلود نشان می‌دهد؛ و اگر هنوز پروژه نساخته‌اید، شروع سریع از صفر تا اولین درخواست چند دقیقه بیشتر نیست.

سوالات متداول

کد یکبار مصرف چقدر اعتبار دارد؟
پنج دقیقه. بعد از ۳ تلاش اشتباه هم کد قفل می‌شود و باید کد جدید گرفت. هر شماره در هر ۱۰ دقیقه حداکثر ۳ بار می‌تواند کد بگیرد تا اندپوینت ارسال، ابزار بمباران پیامکی نشود.
اگر کاربر قبلاً ثبت‌نام نکرده باشد چه می‌شود؟
همان اولین تأیید موفق، حساب را با شماره موبایل می‌سازد و توکن برمی‌گرداند. ثبت‌نام و ورود یک جریان‌اند و فرم ثبت‌نام جدایی لازم نیست — برای اپ موبایل این یعنی حذف پرریزش‌ترین صفحه‌ی مسیر کاربر.
هزینه‌ی پیامک با کیست و پنل پیامکی جدا لازم است؟
نه. ارسال پیامک داخل سرویس انجام می‌شود و بهای هر ارسال از کیف‌پول همان حساب کم می‌شود — مصرفی، نه سهمیه‌ی ماهانه، پس ماهی که پیامکی نرود هزینه‌ای هم ندارد. قرارداد جدا با پنل پیامکی، خرید شماره‌ی خدماتی و نگه‌داری کلید یک سرویس دیگر حذف می‌شود.
ورود با کد پیامکی امن است؟
برای اپ‌های مصرفی بله، به شرط رعایت انقضا، سقف تلاش، سقف ارسال و هش‌شدن کد. ولی بدانید ویرایش چهارم سند NIST SP 800-63B در مرداد ۱۴۰۴ احراز هویت از راه شبکه‌ی تلفن را «محدود» اعلام کرده، چون سیم‌کارت و شماره قابل جابه‌جایی‌اند. اگر پشت ورود، پول یا داده‌ی حساس هست، پیامک را تنها عامل نگذارید و همیشه یک روش ورود جایگزین در دسترس بگذارید.
می‌شود هم ورود با رمز داشت هم ورود با کد پیامکی؟
بله، هر دو روی یک حساب کار می‌کنند و هر کدام را بخواهید می‌توانید از پنل پروژه خاموش کنید. بازیابی رمز عبور هم با همین کد پیامکی انجام می‌شود.

مطالب مرتبط