پروژه SSO و SLO
سناریو کلی :
- پس از redirect شدن کاربر به سمت سامانه بر روی آدرس oauth/authorize/ کاربر را به / ریدارکت میکنیم و کنترلری برای اینکار نوشته شده که index.html حاوی انگولار را بر میگرداند.
- بعد از لود شدن صفحه انگولار درخواستی تحت عنوان initiate-login داده میشود که در آن اطلاعات موردنیاز برای صفحه لاگین و آدرس صفحه بعدی داده میشود
- پس از واردنمودن کدملی دکمه ادامه زده میشود که در آن آدرس صفحه بعدی از پاسخ سرویس قبلی فراخوانی میشود که در مرحله اول send/otp/ است
- پس از وارد کردن کد پیامکی توسط کاربر سرویس authenticate/first-page/ فراخوانی میشود و در صورت موفقیت آمیز بودن کلاینت درخواست آخر برای احرازهویت یعنی /login را میزند.
- در پاسخ این درخواست کاربر هدایت میشود به آدرس oauth/authorize/ که اول درخواست آن را داده بود و پس از آن به نهادمتکی که از آنجا اومده بود هدایت میشود.
جزئیات مراحل :
تمامی سرویسها نیاز است که مقدار cookie نشست برروی درخواست موجود باشد پس انگولار بر روی درخواستهای خود cookie را نیز ارسال میکند (نکتهای است که مقدار نشست در لیست cookieها قابل دسترسی در client نیست به علت httppnly بودن و مقدارش را client نمیتواند بفهمد و فقط در هر درخواست cookie را ارسال میکند).
در مورد توکن csrf :
بر روی cookie مقداری به نام XSRF-TOKEN قرار گرفته است که مقدارش برابر با توکن csrf است حال این کوکی دارای httponly برابر با false است بدین معنی که client میتواند به آن دسترسی پیدا کند. پس کلاینت باید مقدار آن را از کوکی خوانده و در هدر درخواستهای POST خود و تحت عنوان X-XSRF-TOKEN قراردهد و سمت سرور برابری مقدار کوکی و هدر درخواست چک میشود
سرویس initiate login
آدرس سرویس : initiate-login/
بدنه درخواست : ندارد
متد : POST
نوع محتوا : application/x-www-form-urlencoded
پاسخ :
{ "next_page": "login", "next_page_action": "http://192.168.1.118:8095/send/otp", "next_page_data": { "login": { "user_info": { "loa": "LEVEL_2_2", "fields": { "mobile_number": { "priority": 1, "value": "09127998974", "status": "hidden" }, "national_number": { "priority": 2, "value": "", "status": "present" } } }, "client_info": { "scope_titles": "تلفن همراه، کد ملی", "client_name": "ايران", "client_id": "abara" }, "general_info": { "download_address": "http://192.168.1.118:8095/download", "deprecate_address": "http://192.168.1.118:8095/deprecate/" } } }, "ready_for_final_authenticate": false }
توضیح پاسخ :
با فراخوانی این سرویس مشخص میشود که اصلا کاربر میتواند صفحه لاگین را ببیند یا اگر پاسخ خطا داشت صفحه خطا را ببیند یا صفحه لاگین را با حالت خطا ببیند.
- فیلد next_page نشان دهنده صفحه موردنظر است که چون ابتدا کاربر در صفحهای نیست به صفحه لاگین میرود
- فیلد next_page_action نشان دهندهی آدرسی است که با زدن دکمه ادامه یا ورود صفحه بعد فراخوانی میشود
- در قسمت next_page_data اطلاعات صفحه موردنیاز در next_page قرار دارد و این اطلاعات با زیر بخشی مشابه اسم next_page در next_page_data قرار میگیرد و بدان دلیل که الان قرار است صفحه لاگین فراخوانی شود مقدار next_page و زیر بخش next_page_data هر دو login است ولی اگر قرار بود صفحه otp یا pushotp نشان دادهشود این مقدار فرق میکرد.
- در قسمت user_info زیر بخش login اطلاعات کاربر قرار دارد که مجموعهای از فیلدها موجود در صفحه به همراه وضعیت نمایش و الویت نشان دادن در صفحه (priority) و مقدار آنها قرارگرفته است (به جامعتر شدن صفحه کمک می کند که فرانت درگیر loaهای مختلف نشود و فقط فیلدها را با وضعیتشان نشان دهد)
- در قسمت client_info اطلاعات نهاد متکی قراردارد
- در قسمت general_info اطلاعات موردنیاز برای صفحه مانند آدرس فراخوانی سرویس دانلود یا آدرس deprecate میباشد.
- فیلد ready_for_final_authenticate برابر false است و بدین معنی است که مراحل احرازهویت کاربر به اتمام نرسیدهاست.
نمونه پاسخ غلط (وقتی کاربر نیاز دارد فرآیند را از اول شروع کند)
{ "next_page": "error", "ready_for_final_authenticate": false, "error": { "reason": "اجازه دسترسی برای شما وجود ندارد، فرآیند را دوباره شروع کنید." } }
- در قسمت error در صورتی که خطایی رخ داده باشد این فیلد در پاسخ قرار میگیرد و در صورت موفقیت آمیز بودن درخواست اثری از آن نیست.
- فیلد reason : نشان دهنده دلیل خطاست.
- فیلد next_page : وقتی برابر صفحه error باشد حالتی است که در آن باید کاربر را به صفحه error برد و در آنجا مقدار فیلد reason را در آن صفحه نشان داد.
- فیلد next_page : وقتی برابر صفحه ای مثل login, otp و یا push otp باشد باید مقدار خطا (reason) را در آن صفحه به صورت toast نشان دهد (اگر مقدار فیلد next_page با صفحه جاری برابر بود به طبع دیگر نیازی به تغییر صفحه نیست و همانجا باید پیام خطا toast شود)
اگر پاسخ با وضعیت 422 دریافت شد کاربر به آدرس موجود در بدنه پاسخ هدایتشود.
{ "redirect_address":"https://google.com" }
سرویس ارسال پیامک
آدرس سرویس : send/otp/
بدنه درخواست : اطلاعات کدملی (national_number) و شماره موبایل (mobile_number) به صورت form-urlencoded
متد : POST
نوع محتوا : application/x-www-form-urlencoded
پاسخ :
{ "next_page": "otp", "next_page_action": "http://192.168.1.118:8095/authenticate/first-page", "next_page_data": { "otp": { "code_expire_time": "45", "total_code_expire_time":"60", "otp_address": "http://192.168.1.118:8095/send/otp", "mobile_number": "09121234567", "remaining_wrong_attempt": 3 } }, "ready_for_final_authenticate": false }
توضیح پاسخ :
- فیلد next_page : صفحه بعدی otp را نشان میدهد .
- فیلد next_page_action : آدرسی که دکمه موجود در صفحه otp برای واردنمودن کد دریافت شده توسط کاربر را نشان میدهد
- فیلد next_page_data : اطلاعاتی که در صفحه آتی (اینجا otp) است را مانند شماره موبایل، مدت زمان انقضا کد ارسال ( بر اساس ثانیه ) و کل مدت زمان انقضا کد (بر اساس ثانیه) و آدرس دکمه ارسال مجدد(otp_address) و تعداد دفعات اشتباه مجاز (remaining_wrong_attempt) که در متن "در صورت اشتباه وارد کردن به صفحه ussd ارسال میشوید" باید به صورت عدد نوشتاری قرار دادهشود در نسخههای قبلی از littleNumber استفاده میشد را نشان میدهد.
اگر پاسخ با وضعیت 422 دریافت شد کاربر به آدرس موجود در بدنه پاسخ هدایتشود.
{ "redirect_address":"https://google.com" }
سرویس احرازهویت اطلاعات صفحه اول (first-page)
آدرس سرویس : authenticate/first-page/
بدنه درخواست : کد واردشده (code) و اطلاعات کدملی (national_number) و شماره موبایل (mobile_number) به صورت form-urlencoded
متد : POST
نوع محتوا : application/x-www-form-urlencoded
پاسخ :
{ "next_page": "otp", "next_page_action": "http://192.168.1.118:8095/login", "ready_for_final_authenticate": true }
توضیح پاسخ :
- فیلد next_page برابر صفحه جاری قرار گرفت برای اینکه انتقال صفحهای دیگر نداشته باشیم زیرا مقدار ready_for_final_authenticate برابر true شده است و منظور آن است که تمام مراحل موردنیاز احرازهویت به اتمام رسیدهاست.
- با فراخوانی http://192.168.1.118:8095/login کاربر redirect میشود به آن نهادمتکی که از آماده است و آخرین مرحله ارتباط angular کلاینت در این نقطه است.
پاسخ خطا ( در صورتی که کاربر بیش از حد کد پیامکی را اشتباه واردکند و نیاز باشد صفحه pushotp نمایش دادهشود)
{ "next_page": "push_otp", "next_page_action": "http://192.168.1.118:8095/authenticate/first-page", "next_page_data": { "push_otp": { "code_expire_time": "173", "total_code_expire_time":"180", "otp_address": "http://192.168.1.118:8095/send/otp", "push_code_value": "108460", "mobile_number": "09121234567", "push_code_provider": "*725#", "push_otp_check_status_interval": 2, "dial_number":"*725*108460#" } }, "ready_for_final_authenticate": false, "error": { "reason": "کد اشتباه ارسال شده و تعداد دفعات خطا 1 میباشد" } }
پاسخ خطا (در صورتی که شاهکار اطلاعات کاربر را قبول نکند)
{ "next_page": "login", "next_page_data": { "login": { "user_info": { "loa": "LEVEL_2_2", "fields": { "mobile_number": { "priority": 1, "value": "09127998974", "status": "hidden" }, "national_number": { "priority": 2, "value": "0016873408", "status": "present" } } }, "client_info": { "scope_titles": "تلفن همراه، کد ملی", "client_name": "ايران", "client_id": "abara" }, "general_info": { "download_address": "http://192.168.1.118:8095/download", "deprecate_address": "http://192.168.1.118:8095/deprecate/" } } }, "ready_for_final_authenticate": false, "error": { "reason": "این شماره موبایل با کدملی سازگار نمی باشد. تعداد دفعات خطا 1" } }
در این حالت کاربر صفحه لاگین را میبیند و در آنجا پیام خطا toast میشود و اطلاعات موردنیاز هر صفحه در قسمت next_page_data قرار میگیرد.
پاسخ خطا (در صورتی که کد پیامکی اشتباه زده باشد)
{ "next_page": "otp", "next_page_action": "http://192.168.1.118:8095/authenticate/first-page", "next_page_data": { "otp": { "code_expire_time": "20", "total_code_expire_time":"60", "otp_address": "http://192.168.1.118:8095/send/otp", "mobile_number": "09124958820" } }, "ready_for_final_authenticate": false, "error": { "reason": "کد به درستی وارد نشده است. تعداد دفعات خطا 1" } }
در این حالت کاربر در صفحه otp میماند و پیام خطا نشان داده میشود.
پاسخ درست (حالتی که مرحله بعد صفحه تشخیص چهره باشد)
{ "next_page": "facedetection", "next_page_action": "http://192.168.1.118:8095/authenticate/face-decetion", "next_page_data": { "facedetection": { ... } }, "ready_for_final_authenticate": false }
در این حالت کاربر به صفحه تشخیص چهره هدایت میشود
اگر پاسخ با وضعیت 422 دریافت شد کاربر به آدرس موجود در بدنه پاسخ هدایتشود.
{ "redirect_address":"https://google.com" }
سرویس login نهایی
آدرس سرویس : login/
بدنه درخواست : ندارد
متد : POST
نوع محتوا : application/x-www-form-urlencoded
پاسخ : اگر پاسخ با وضعیت 200 دریافت شد نشان دهندهی موفقیت آمیز بودن عملیات است و کاربر باید به آدرسی که در بنده درخواست است ریدایرکت شود ولی اگر پاسخ دیگری دریافت شد نشان دهندهی خطاست وهمانند پاسخهای خطای سرویسهای قبلی با آن رفتار شود.
{ "redirect_address" : "http://192.168.1.118:8095/...." }
اگر پاسخ با وضعیت 422 دریافت شد کاربر به آدرس موجود در بدنه پاسخ هدایتشود.
{ "redirect_address":"https://google.com" }
سرویس zoom-id-init
آدرس: /authenticate/face-detection/zoom-id-init
توضیح: این سرویس باید در ابتدای لود شدن فرم zoomid فراخوانی شود.
بدنه درخواست: ندارد
متد: POST
محتوای پاسخ:
مقدار is_enrolled مشخصکننده نمایش/عدم نمایش inputهای تاریخ تولد و سریال کارت ملی در این فرم است. در صورت true بودن این مقدار، نیازی به نمایش این inputها نیست.
مقدار ramaining_wrong_attemp نیز تعداد خطای ممکن ثبتنام/تطابق چهره را مشخص میکند.
مقدار next_page_action در صورت true بودن is_enrolled برابر/authenticate/face-detection/zoom-id و در غیر این صورت برابر /authenticate/face-detection/register خواهد بود
نمونه پاسخ موفق در صورت enrolled نبودن:
{ "next_page": "zoomid", "next_page_action": "/authenticate/face-detection/register", "next_page_data": { "zoomid": { "is_enrolled": false, "remaining_wrong_attempt": 3 } }, "ready_for_final_authenticate": false }
نمونه پاسخ موفق در صورت enrolled بودن:
{ "next_page": "zoomid", "next_page_action": "/authenticate/face-detection/zoom-id", "next_page_data": { "zoomid": { "is_enrolled": true, "remaining_wrong_attempt": 3 } }, "ready_for_final_authenticate": false }
نمونه پاسخ ناموفق (در صورتی که فراخوانی سرویس zoomid با خطای Timeout مواجه شود):
{ "next_page": "zoomid", "next_page_action": "/authenticate/face-detection/zoom-id-init", "next_page_data": { "zoomid": { "remaining_wrong_attempt": 3 } }, "ready_for_final_authenticate": false, "error": { "reason": "سرور تشخیص چهره در دسترس نیست" } }
نمونه پاسخ ناموفق (در صورتی که فراخوانی سرویس zoomid با خطای ناشناخته مواجه شود):
{ "next_page": "error", "ready_for_final_authenticate": false, "error": { "reason": "خطا در فراخوانی سرویس تشخیص چهره" } }
سرویس ثبت نام zoom-id
آدرس: /authenticate/face-detection/register
توضیح: این سرویس در صورتی مورد استفاده قرار میگیرد که در پاسخ zoom-id-init مقدار is_enrolled برابر false باشد و نیاز به ثبت نام کاربر باشد. تاریخ تولد و سریال کارت ملی کاربر در بدنه این درخواست قرار میگیرند.
بدنه درخواست: به صورت application/x-www-form-urlencoded شامل: تاریخ تولد با نام birth_date به صورت timestamp و سریال کارت ملی با نام national_serial به صورت رشته.
متد: POST
محتوای پاسخ: در صورتی که is_enrolled در پاسخ true باشد به معنی موفقیت در ثبت نام کاربر است. در صورت خطا هم remaining_wrong_attempt تعداد خطای ممکن باقیمانده را مشخص میکند.
نمونه پاسخ موفق:
{ "next_page": "zoomid", "next_page_action": "/authenticate/face-detection/zoom-id", "next_page_data": { "zoomid": { "is_enrolled": true, "remaining_wrong_attempt": 3 } }, "ready_for_final_authenticate": false }
نمونه پاسخ ناموفق در صورت تطابق نداشتن اطلاعات کاربر:
{ "next_page": "zoomid", "next_page_action": "/authenticate/face-detection/register", "next_page_data": { "zoomid": { "is_enrolled": false, "remaining_wrong_attempt": 2 } }, "ready_for_final_authenticate": false, "error": { "reason": "اطلاعات کاربر تطابق ندارند" } }
نمونه پاسخ ناموفق در صورت بیش از حد اشتباه وارد کردن اطلاعات کاربر با کد ۴۲۲ که در این حالت کاربر باید به آدرس موجود در پاسخ هدایت شود:
{ "redirect_address": "http://divar.com:9000/buy?error=too_many_attempt" }
سرویس احراز هویت zoom-id
آدرس: /authenticate/face-detection/zoom-id
توضیح: این سرویس برای تعیین وضعیت احراز هویت کاربر پس از فراخوانی سرویس تطابق چهره توسط ماژول zoomid استفاده میشود. در callback فراخوانی سرویس تطابق چهره ماژول zoomid، با فراخوانی این سرویس وضعیت احراز هویت کاربر بررسی میشود.
بدنه درخواست: ندارد
متد: POST
محتوای پاسخ: در صورتی که از قبل کاربر با موفقیت سرویس تطابق چهره را فراخوانی کرده باشد، مشابه سایر سرویسهای احراز هویت، مقدار ready_for_final_authentication با مقدار true برگردانده میشود. در غیر این صورت هم مقدار emaining_wrong_attempt تعداد خطای ممکن باقیمانده را مشخص میکند.
نمونه پاسخ موفق:
{ "next_page": "zoomid", "next_page_action": "/login", "ready_for_final_authenticate": true }
نمونه پاسخ ناموفق در صورتی که چهره کاربر تطابق نداشته باشد:
{ "next_page": "zoomid", "next_page_action": "/authenticate/face-detection/zoom-id", "next_page_data": { "zoomid": { "is_enrolled": true, "remaining_wrong_attempt": 3 } }, "ready_for_final_authenticate": false }
نمونه پاسخ ناموفق در صورت اتمام تلاشهای ممکن برای تطابق چهره با کد ۴۲۲ که در این حالت کاربر باید به آدرس موجود در پاسخ هدایت شود:
{ "redirect_address": "http://divar.com:9000/buy?error=too_many_attempt" }
6 Comments
عرفان گلدوزیان
در قسمت سرویس zoom-id-init
نمونه پاسخ ناموفق در صورت تطابق نداشتن اطلاعات کاربر، چرا به صفحه اول برگردانده شدهاست؟ ما در هیچ صورتی به صفحه اول دیگر بر نمیگردیم، یا به صفحه error میرویم یا در همانجا اگر صفحه load شده است خطا نشان میدهیم
محمدجواد دارسنج
اصلاح شد
عرفان گلدوزیان
در سرویس تعیین وضعیت zoom-id
در توضیح زیر:
محتوای پاسخ: در صورتی که is_enrolled در پاسخ true باشد به معنی موفقیت در ثبت نام کاربر است. در صورت خطا هم remaining_wrong_attempt تعداد خطای ممکن باقیمانده را مشخص میکند.
وقتی موفقیتآمیز باشد کل فرآیند نمونه پاسخ لاگین نهایی باز میگردد، اگر خطا بخورد که نمونه پاسخ خطا برگردانده میشود که در آن یا is_enrolled برابر false یا true است که فرقی به حال ما ندارد، در هر صورت مشکل داشته فرآیند match خود zoom-id پس توضیح is_enrolled در پاسخ true باشد به معنی موفقیت در ثبت نام کاربر است، اشتباه است.
محمدجواد دارسنج
به نظر اصلاح شد
عرفان گلدوزیان
نام سرویس تعیین وضعیت zoom-id به سرویس احرازهویت zoom-id تغییریابد، زیرا هم مکانیزم ثبت نام را دارد و هم مکانیزم احرازهویت
محمدجواد دارسنج
اصلاح شد