چجوری OAuth 2.0 کار می کنه و کدام روش رو انتخاب کنیم؟
پیش نوشت۱: ۱۰ یا ۱۱ ماه پیش بود که می خواستم بخش لاگین چندپر رو با نود جی اس بنویسم...خب اون موقع من مبتدی بودم و در حال یادگیری (هنوز هم هستم) به هر صورت با JWT و روشی توکن بیس ابداعی چیز بدی از آب در نیومد ولی همین چند وقت پیش مقاله ای رو توی سایت Medium دیدم که خیلی ساده و عالی این موضوع رو توضیح داده. من هم تصمیم گرفتم ترجمه اش بکنم تا هم خودم بهتر یاد بگیرم و این که شاید به درد کسای دیگه ای بخوره تا مثل من توی انبوهی از روش های پیچیده ی لاگین سردرگم نشن! از خط بعدی ترجمه ی بنده از متن اصلی مقاله مربوطه هست که می خوانید:
پیش نوشت۲: هم من و هم شمایی که داری می خونی احتمال زیاد برنامه نویسی می کنی و خب ... ! کد می خوایم ولی به هر حال هدف این نوشته نیست ولی می تونه فضایی فراهم بشه برای پرسش و پاسخ و جستجوی هدفمند
این مقاله نمی خواد که راهنمای کاملی برای OAuth 2.0 باشه بلکه تنها یک مقدمه ای برای نشان دادن مسیر های کاربران و این که چه مراحلی توی OAtuth 2 برای کاربر هست تا لاگین بکنه. ما می خواهیم با مشاهده و بررسی ۴ چارچوب در قالب مثال این موضوع رو به بررسی کنیم. و در نهایت هدف این نوشته این است که بتوانیم بهترین روش رو برای پروژه مون انتخاب کنیم.
آن چه که تا بحال من متوجه شدم و از بزرگان این حوزه فراگرفتم! به طور کلی می توانیم ۴ ورژن یا روش اجرای OAuth 2.0 را نام ببریم. البته بدین معنا نیست که باید همه ی این روش ها رو اجرا کنیم بلکه یکی از این موارد کافیست. نکته اینجاست که هدف مشترک این ۴ روش به درست آوردن access token و استفاده ی از آن برای دسترسی به اطلاعات و احراز هویت است. همین و بس... این ۴ روش به شرح زیر است:
این مسیر احزار هویت کامل ترین و پیچیده ترین روش از انواع روش های OAuth2 است. مراحل لاگین در دو مرحله و با تضمین حد بالایی از امنیت انجام می شود.
بیاید به همراه جزییات نحوه ی کار این روش لاگین رو در ادامه بررسی کنیم:
۱- کاربر می خواهد لاگین کند
یک سناریوی کلاسیک برای این روش توسط کاربر در مرورگر اجرا می شه. کاربر روی دکمه ی «لاگین با OAuth» کلیک می کنه و درخواست کاربر توسط کلاینت (در این مثال سایت) به سمت سرور احراز هویت ارسال می شه.
۲- کاربر به سرور احراز هویت منتقل (redirect) می شود
کلاینت درخواست لاگین رو به سرور احراز هویت می فرستد. این request به صورت فرم HTTP redirect و اطلاعات آن با متد GET به این سرور ارسال می شود (به مثال زیر توجه کنید)
GET /token
Location: https://the-authorization-server/token?client_id=[the_client_id]&redirect_uri=[a redirect uri]&response_type=code&scope=[list of scopes]&state=[some client parameter]
پارامتر های ارسالی:
۳- اعتبار سنجی درخواست لاگین (Request validation)
سرور احراز هویت بایستی تمامی پارامتر های لاگین را بررسی کند:
پیشاپیش ذخیره ی کلاینت های در دسترس برای بررسی و هندل کردن این موارد ضروری است. و البته نگه داری و مدیریت اطلاعات کلاینت ها از حیطه ی وظایف OAuth خارج است.
۴- فرم لاگین
سرور احراز هویت فرم لاگین را به کاربر نشان می دهد و کاربر نام کاربری و رمز عبور خود را برای ورود به برنامه وارد می کند (مرحله ی ۵ در عکس)
بعد از بررسی اطلاعات توسط سرور احراز هویت (مرحله ی ۶ در عکس) اجازه ی دسترسی به scope مشخص شده را به کاربر می دهد و request خارج از اون scope تعیین شده مجاز نیست (چون ممکنه در استفاده از اپلیکیشن محدود شده باشه)
۵- انتقال (redirect) به کلاینت با کد مجوز authorization_code
سرور احراز هویت کد authorization code را ایجاد می کند و آن را روی redirect_url تعیین شده به سمت کلاینت بر می گرداند.
تمامی این مراحل در سمت کلاینت اتفاق می افتد (روی مرورگر یا اپلیکیشن موبایل) و در تمامی این مراحل کلاینت باید با بک اند در ارتباط باشد.
یه نظر من این موارد یکی از مهم ترین جنبه های انتخاب روش مناسب OAuth 2.0 برای پروژه هاست که یبا نیاز هامون منطبق بشه.
۸ , ۹- اعتبار سنجی کد مجوز (authorization code)
در اینجا کلاینت باید سرور احراز هویت را برای بررسی کد دریافت شده فراخوانی کند. برای این کار ارسال پارامتر های زیر لازم است:
سرور احراز هویت تمامی اطلاعات بالا را از جهت صحت داشتن و همخوانی بررسی می کند. بررسی کد مربوطه باید از جهات کامل بودن و خطر دار نبودن و منتقضی نبودن و تعلق داشتن به کلاینت بررسی شود.
۱۰- کلاینت access_token را دریافت می کند
سرور احراز هویت access_token را ایجاد کی کند و آن را به سمت کلاینت بر می گرداند. انواع مختلفی برای ایجاد توکن وجود دارد. این ها می توانند تاریخ انقضا داشته باشند یا رفرش شوند. عموما همراه access_token اطلاعات زیر نیز به کلاینت برگردانده می شود:
۱۱- کلاینت از access_token استفاده می کند
از این مرحله به بعد کلاینت access_token رو دریافت کرده و از آن برای دسترسی و شناسایی توسط سرور منابع (همون جایی که اطلاعات رو از دیتابیس می گیره و به کلاینت بر می گردونه) مورد استفاده قرار می گیرد.
سرور منابع یک بخشی از وب اپلیکیشن سمت سرور ماست که فرقی نمی کنه که از چه نوعی باشه می تونه RESRT API یا SOAP یا هر چیز دیگه ای باشه ... متد درخواست تغییر access_token بستگی به نوع منابع تون داره. متد متداول استفاده از REST API هست (در حال حاظر) با بهره گیری از HTTP header:
مثال (در هدر قرار گرفته است):
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ
۱۲ و ۱۳- اعتبار سنجی توکن
هر وقتی که سرور منابع درخواستی را دریافت می کند بایستی توکن از لحاظ اعتبار خود توکن و کلاینت آن اطمینان حاصل کند.
اعتبار سنجی توکن بسته به نوع ایجاد آن می تواند به روش های مختلفی صورت گیرد. این اعتبار سنجی می تواند در همان سرور منابع یا با فراخوانی سرور احراز هویت انجام شود.
به هر حال به معماری برنامه تون بستگی داره و در سمت کلاینت تفاوتی نشون داده نمی شه. اگر می خواید از روش OAuth برای احراز هویت کاربران استفاده کنید بهتره به نمونه های مربوط به نوع معماری برنامه تون مراجعه کنید تا انتخاب آگاهانه تر و کد های مناسب تری داشته باشید.
۱۴ و ۱۵- دسترسی و نمایش منابع اختصاصی
اطلاعات مخصوص با دسترسی محدود به کلاینت در هر بار اعتبار سنجی توکن توسط سرور منابع به کاربر نمایش داده خواهد شد.
این روش مشابه روش قبلی (کد مجوز) است با این تفاوت که در روش ضمنی access_token بلافاصله پس از لاگین کاربر به سمت کلاینت ارسال می شود. از این روش در Single Page Applications ها مثل انگولار یا ری اکت یا ویو جی اس (نرم افزار هایی که از فریم ورک های جاوااسکریپت استفاده می کنن) استفاده می شود چرا که امکان محرمانه نگه داشتن client_secret وجود ندارد (که در روش اول که کد مجوز بود بحث شد)
اولبن تفاوت هنگام redirect شدن به سرور احراز هویت مشاهده می شود. مقدار پارامتر response_type از code به token تغییر یافته است. این بدین معناست که نوع پاسخ سرور بایستی بلافاصله access_token باشد به جای authorization_code.
در این روش مراحل کمتری نسبت به روش قبلی برای لاگین کاربر طی می شود اما در عین حال به علت طی شدن مراحل ثبت نام در مروگر امنیت کمتری نسبت به روش قبلی (کد توکن) دارد. مثلا token رد و بدل می شود در حالی که در روش کد مجوز به این صورت نیست و توکن بین درخواست های سرور ها منتقل می شود بنابراین دسترسی یا اختلال در آن بسیار دشوارتر است.
تفاوت اصلی این روش در این است که کاربر در مراحل احراز هویت دخیل نیست و برنامه مستقیما خودش اقدام می کند.
این بدین معناست که نیازی به انجام کاری جلوی چشم کاربر ندارد بلکه همه ی مراحل فقط و فقط در پشت صحنه طی می شود.
این روش در سمت سرور اجرا می شود (نه در سمت کلاینت). redirect نداریم اما یک درخواست با متد POST با پارامتر های زیر ارسال می شود.
client_credentials
POST /token
&client_id=my-fancy-client-application &client_secret=xxxxxxx &grant_type=client_credentials
پاسخ دریافتی از سمت سرور access_token می تواند در درخواست های از سرور منابع مورد استفاده قرار گیرد.
بحث اصلی در این روش به نظر من اینه که کاربر در مرورگر (سمت کلاینت) نام کاربری و رمز عبور خود را وارد می کنه (نه در سرور احراز هویت). نکته ای لازمه در اینجا اشاره بشه اینه که اطلاعات محرمانه (credentials) به سرور احراز هویت تعلق داره نه به کلاینت.
این نکته بدین معناست که کاربر باید به طور کامل از جهت ارسال اطلاعات به سرور احراز هویت معتبر اطمینان حاصل کنه. برای فهم بهتر تصور کنید که برنامه ی شما قابلیت ثبت نام با اکانت فیسبوک را دارد این در حالی است که کاربر بایستی نام کاربری و رمز عبور اکانت فیسبوک خود را در برنامه شما وارد کنید. اگر شما جای این کاربر بودید چه می کردید؟ (خب ... ! اطلاعاتم رو وارد سایته می کردم!) در این وضعیت باید از جعلی نبودن سایت و عدم ذخیره یا تغییر در رمز عبور و نام کاربری اکانت فیسبوک خود توسط سایت اطمینان خاطر پیدا کنید.
اگر درست در خاطرم باشه اسپاتی فای همچن فیچری داشت کاربران مستقیما با اکانت فیسبوک شون تو اسپاتی فای لاگین می کردند.
در یک مرحله نام کاربری و رمز عبور توسط سمت کلاینت (فرانت) دریافت و به سمت سرور (بک اند) ارسال می شود. با استفاده از متد POST و پارامتر های زیر این درخواست انجام می شود:
password
مثال:
POST /token
grant_type=password &username=username@authorization-server.com &password=TheUserPassword &client_id=my-fancy-client-app &client_secret=xxxxxxx
سرور احراز هویت پس از بررسی نام کاربری و رمز عبور access_token را به کلاینت برمی گرداند.
در این روش به دخالت هر دو سمت سرور و کاتینت نیاز است.
برای اجرای OAuth 2 به همکاری و توسعه در هر دو سمت کلاینت و سرور در زمینه های زیر نیاز است:
در خاطر تون باشه که همیشه در تمامی این روش ها نیاز به رمز عبور کاربر هست و در نتیجه برای ذخیره ی این اطلاعات محرمانه نیاز به سرور احساس می شه. در مواردی که امکان سرور داشتن وجد نداره مثل اپلیکیشن های موبایل یا وب سایت های جاوااسکریپتی که شرایط متفاوتی دارند باید این مشکل رو با یک سرور اختصاصی برای این موضوع یا با روش های رمز نگاری حل کرد.
فریم ورک ها و زبان های برنامه ویسی زیادی هستند که OAuth رو اجرا می کنن. این امر کارو در اجرای روش و اعتبار سنحی هایی که نیاز دارید (طرح کلی و کد های مربوط) راحت تر می کنه. اما من به ندرت راه حل های «هلو برو تو گلو !» (مثل آب خوردن) پیدا کردم.
یک چالش در اجرا می تواند پیکربندی و مدیریت کلاینت های متفاوت باشد که تنها با تصور کردن این موضوع می توانید به سرعت این نکته رو تصدیق کنید.
علاوه بر آن باید به scope و سطوح دسترسی مجوز های کاربران نیز توجه کنید. جای مدیریت این موضوع هر جایی می تونه باشه ولی ظریف تر این است که در مرحله ی حفاظت از منابع (در سرور منابع) اجرا شود.
نکته ی دیگر مزایای مدیریت token هاست که مانند یک دیتابیس عمل می کند و قابلیت ذخیره ی یک دوره ی کامل چرخه ی حیات کاربر را داراست.
انتخاب روش درست به عوامل متعددی بستگی داره. پاسخ به این سوالات می تواند به انتخاب درست شما منجر شود.
آیا شما می توانید client_secret را به صورت امن نگهداری کنید؟
بله: سوال بعدی
خیر: روش ضمنی IMPLICIT GRANT
آیا برنامه ی شما وب اپلیکیشن است؟
بله: سوال بعدی
خیر: روش کد مجوز CLIENT CREDENTIAL GRANT
آیا کاربر اعتماد کافی جهت ورود اطلاعات محرمانه ی کاربری خود را دارد؟
بله: روش پسورد PASSWORD GRANT
خیر: روش CLIENT CREDENTIAL GRANT
امیدوارم این مقاله به دردتون خورده باشه و تبریک می گم که به آخرش رسیدید و این برای من بدین معناست که این نوشته به درد خیلیا خورده و تونسته کمکی هر چند کوچک به شمار بیاد.
منبع: An OAuth 2.0 introduction for beginners
پس نوشت۱: منم خیلی خوشحالم که بالاخره ترجمش تموم شد چون حدود یک ماه طول کشید (هفته ای یه روز وقت گذاشتم) و هر بخش رو هم که ببینید لحن متن متناسب با حال اون موقع من متفاوته! و البته می دونم کیفیت پایینی هم داره :o
پس نوشت۲: اخیرا یک آهنگی گیر آوردم که برام خیلی جذاب بود از لحاظ معنی و مفهومش. می گه که روزا می گذره و اینو همه هم می دونن ولی تو نصف عمرت رو می خوای از هر کسی یاد بگیری و در نهایت خدا تو رو به اون چیزی که تو رویاهات هست می رسونه... لینک soundcloud به این آهنگ Dream On - Aerosmith
موفق باشید ... فقط همین!