وبسرویسهای Auth Push آزمایشی
مرجع ساده و کامل درخواستهای سروری Auth Push؛ ثبت دستگاه مورد اعتماد، ساخت درخواست ورود، بررسی نتیجه و حذف اعتماد دستگاه.
قبل از استفاده این نکات را بدانید
همه درخواستهای این صفحه باید از سرور سایت شما فرستاده شوند. هر درخواست به کلید عمومی و کلید خصوصی همان سرویس نیاز دارد. شناسه واقعی کاربر را از دیتابیس یا نشست معتبر خودتان بردارید و هیچوقت اجازه ندهید مرورگر آزادانه آن را تعیین کند.
۱. راهنمای کاربر
Auth Push چیست، چگونه فعال میشود و کاربر چطور ورود را تأیید میکند.
۲. راهنمای توسعهدهندگان
روش اتصال صفحه ورود، بررسی وضعیت، کد Push و بازگشت به پیامک.
۳. وبسرویسها
درخواستهای سروری برای ثبت دستگاه، ساخت درخواست ورود و تأیید نهایی.
| مسیر | به زبان ساده چه کاری میکند؟ |
|---|---|
| POST /auth-push/bind | دستگاه فعلی را بهعنوان دستگاه مورد اعتماد یک کاربر ثبت میکند. |
| POST /auth-push/unbind | اعتماد دستگاه را برمیدارد و درخواستهای باز آن را باطل میکند. |
| POST /auth-push/challenges | یک درخواست کوتاهمدت برای تأیید مستقیم یا کد ششرقمی میسازد. |
| POST /auth-push/grants/consume | مجوز یکبارمصرف را بررسی میکند تا سرور بتواند کاربر را وارد کند. |
ترتیب معمول فراخوانی وبسرویسها
ثبت دستگاه مورد اعتماد
بعد از ورود معتبر کاربر، سرور مسیر bind را صدا میزند.
ساخت درخواست ورود
در ورود بعدی، سرور با challenges یک درخواست کوتاهمدت میسازد.
انتظار برای پاسخ کاربر
مرورگر با SDK منتظر تأیید یا ورود کد میماند.
بررسی نتیجه نهایی
سرور Grant را با grants/consume بررسی میکند و سپس نشست ورود را میسازد.
حذف اعتماد در زمان لازم
در خروج یا حذف دستگاه، سرور مسیر unbind را فراخوانی میکند.
۲. ثبت دستگاه بهعنوان دستگاه مورد اعتماد
| فیلد | توضیح | الزام |
|---|---|---|
| api_public_key | کلید عمومی سرویس | بله |
| api_private_key | کلید خصوصی سرویس؛ فقط Backend | بله |
| subscriber_id | شناسه پایدار دستگاهی که کاربر روی آن احراز هویت شده است | بله |
| auth_identity | شناسه داخلی و پایدار کاربر در سیستم شما؛ مانند user UUID | بله |
curl -X POST https://pushfa.com/api/webservices/auth-push/bind \
-H "Content-Type: application/json" \
-d '{
"api_public_key": "YOUR_PUBLIC_KEY",
"api_private_key": "YOUR_PRIVATE_KEY",
"subscriber_id": "DEVICE_SUBSCRIBER_UUID",
"auth_identity": "YOUR_USER_UUID"
}'
نمونه اتصال دستگاه در Laravel
در این نمونه، UUID کاربر از نشست احراز هویتشده گرفته میشود و مرورگر اجازه تعیین هویت کاربر را ندارد.
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
Route::post('/account/trusted-device', function (Request $request) {
$data = $request->validate(['subscriber_id' => ['required', 'uuid']]);
Http::asJson()->post('https://pushfa.com/api/webservices/auth-push/bind', [
'api_public_key' => config('services.pushfa.public_key'),
'api_private_key' => config('services.pushfa.private_key'),
'subscriber_id' => $data['subscriber_id'],
'auth_identity' => $request->user()->uuid,
])->throw();
return response()->json(['trusted' => true]);
})->middleware('auth');
۳. ساخت درخواست کوتاهمدت ورود
سرور سایت شناسه کاربر و شناسه دستگاهی را که منتظر ورود است برای پوشفا میفرستد. پوشفا به همان دستگاه اعلان نمیفرستد و حداکثر پنج دستگاه فعال دیگر کاربر را انتخاب میکند. روش درخواست میتواند تأیید مستقیم یا کد ششرقمی باشد.
| فیلد | توضیح | الزام |
|---|---|---|
| api_public_key / api_private_key | کلیدهای سرویس | بله |
| auth_identity | همان شناسه داخلی استفادهشده هنگام bind | بله |
| requester_subscriber_id | Subscriber ID دستگاهی که منتظر ورود است | بله |
| mode | approval برای تأیید روی دستگاه دیگر یا otp برای نمایش کد روی دستگاه دیگر | خیر؛ پیشفرض approval |
| expires_in | زمان اعتبار بین ۶۰ تا ۳۰۰ ثانیه | خیر؛ پیشفرض ۱۲۰ |
| reference | شناسه داخلی درخواست در Backend شما | خیر |
| context[ip/device/location] | اطلاعاتی که در صفحه تأیید به کاربر نمایش داده میشود | خیر |
curl -X POST https://pushfa.com/api/webservices/auth-push/challenges \
-H "Content-Type: application/json" \
-d '{
"api_public_key": "YOUR_PUBLIC_KEY",
"api_private_key": "YOUR_PRIVATE_KEY",
"auth_identity": "YOUR_USER_UUID",
"requester_subscriber_id": "REQUESTER_SUBSCRIBER_UUID",
"mode": "approval",
"expires_in": 120
}'
نمونه Endpoint شروع ورود در Backend
Backend ابتدا کاربر را با شماره موبایل یا شناسه ورود پیدا میکند، auth_identity واقعی را از دیتابیس خودش برمیدارد و Challenge را میسازد. api_private_key هرگز در پاسخ مرورگر قرار نمیگیرد.
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
Route::post('/auth/push/start', function (Request $request) {
$data = $request->validate([
'username' => ['required', 'string'],
'subscriber_id' => ['required', 'uuid'],
'mode' => ['nullable', 'in:approval,otp'],
]);
$user = User::where('username', $data['username'])->firstOrFail();
$response = Http::asJson()->post(
'https://pushfa.com/api/webservices/auth-push/challenges',
[
'api_public_key' => config('services.pushfa.public_key'),
'api_private_key' => config('services.pushfa.private_key'),
'auth_identity' => $user->uuid,
'requester_subscriber_id' => $data['subscriber_id'],
'mode' => $data['mode'] ?? 'approval',
'expires_in' => 120,
'reference' => (string) $user->uuid,
'context' => [
'ip' => $request->ip(),
'device' => $request->userAgent(),
],
]
);
if ($response->status() === 422) {
return response()->json(['fallback_required' => true], 422);
}
return response()->json($response->throw()->json('data'));
})->middleware('throttle:5,1');
۶. بررسی مجوز یکبارمصرف و ورود کاربر
بعد از تأیید، SDK یک Grant کوتاهعمر برمیگرداند. مرورگر آن را برای سرور سایت میفرستد. سرور با کلید خصوصی اعتبار Grant و کاربر مربوط به آن را بررسی میکند و فقط پس از دریافت verified=true نشست ورود را میسازد.
| فیلد | توضیح | الزام |
|---|---|---|
| api_public_key / api_private_key | کلیدهای سرویس | بله |
| challenge_id | شناسه Challenge | بله |
| grant | Grant دریافتی فقط پس از تأیید | بله |
| auth_identity | شناسه داخلی کاربری که قرار است وارد شود | بله |
curl -X POST https://pushfa.com/api/webservices/auth-push/grants/consume \
-H "Content-Type: application/json" \
-d '{
"api_public_key": "YOUR_PUBLIC_KEY",
"api_private_key": "YOUR_PRIVATE_KEY",
"challenge_id": "CHALLENGE_UUID",
"grant": "ONE_TIME_GRANT",
"auth_identity": "YOUR_USER_UUID"
}'
نمونه تکمیل Login در Backend
Route::post('/auth/push/complete', function (Request $request) {
$data = $request->validate([
'challenge_id' => ['required', 'uuid'],
'grant' => ['required', 'string', 'size:64'],
]);
// نگاشت Challenge به کاربر باید در state امن Backend شما نگهداری شود.
$user = resolveUserForChallenge($data['challenge_id']);
$verified = Http::asJson()->post(
'https://pushfa.com/api/webservices/auth-push/grants/consume',
[
'api_public_key' => config('services.pushfa.public_key'),
'api_private_key' => config('services.pushfa.private_key'),
'challenge_id' => $data['challenge_id'],
'grant' => $data['grant'],
'auth_identity' => $user->uuid,
]
)->throw()->json('data.verified');
abort_unless($verified === true, 401);
auth()->login($user);
$request->session()->regenerate();
return response()->json(['redirect_to' => '/dashboard']);
});
حذف اعتماد دستگاه
هنگام خروج از حساب، لغو نشست، تغییر مالک دستگاه یا حذف آن از فهرست دستگاهها، سرور باید اعتماد آن دستگاه را بردارد. این کار درخواستهای باز و مجوزهای استفادهنشده مرتبط را نیز باطل میکند.
curl -X POST https://pushfa.com/api/webservices/auth-push/unbind \
-H "Content-Type: application/json" \
-d '{
"api_public_key": "YOUR_PUBLIC_KEY",
"api_private_key": "YOUR_PRIVATE_KEY",
"subscriber_id": "DEVICE_SUBSCRIBER_UUID"
}'
چکلیست امنیتی Production
| کنترل | الزام |
|---|---|
| کلید خصوصی | فقط در Secret Manager یا متغیر محیطی Backend نگهداری شود. |
| مالکیت هویت | auth_identity فقط از دیتابیس و نشست معتبر Backend استخراج شود، نه از ورودی مرورگر. |
| نگاشت Challenge | Challenge را در Backend به همان تلاش ورود و همان کاربر متصل کنید. |
| Session fixation | پس از مصرف Grant، شناسه Session را regenerate کنید. |
| Rate limit | روی endpointهای داخلی start و complete علاوه بر محدودیت پوشفا، محدودیت IP و حساب اعمال کنید. |
| نمایش درخواست | IP، نوع دستگاه و موقعیت تقریبی را برای تشخیص درخواست ناشناس به کاربر نشان دهید. |
| Fallback | fallback پیامک را فقط پس از لغو Challenge قبلی آغاز کنید. |
| Logout و revoke | در خروج، حذف نشست و تغییر مالک دستگاه، unbind را فراموش نکنید. |
| ثبت رویداد | نتیجه نهایی را بدون ذخیره OTP، client_token، Grant یا api_private_key در audit log ثبت کنید. |
خطاها و رفتار مورد انتظار Backend
| حالت | تفسیر | اقدام |
|---|---|---|
| 422 + fallback_required | دستگاه واجد شرایط وجود ندارد یا ارسال امن ممکن نیست. | Challenge را خطای سیستمی تلقی نکنید و fallback را آغاز کنید. |
| 401/403 | کلیدها، مالکیت سرویس یا دسترسی معتبر نیست. | درخواست را متوقف و تنظیم Secret/Service را بررسی کنید. |
| expired/rejected/cancelled | Challenge دیگر قابل تکمیل نیست. | Grant یا client_token قبلی را استفاده نکنید. |
| consumed | Grant قبلاً یک بار مصرف شده است. | Session قبلی را بررسی و از مصرف دوباره جلوگیری کنید. |
| 429 | محدودیت نرخ اعمال شده است. | Backoff و محدودیت داخلی IP/Account را رعایت کنید. |