صادق محبی
صادق محبی
خواندن ۱۷ دقیقه·۶ سال پیش

روش های احراز هویت توکن بیس لاگین کاربر (راهنمای عملی روش های OAuth2)

چجوری OAuth 2.0 کار می کنه و کدام روش رو انتخاب کنیم؟

پیش نوشت۱: ۱۰ یا ۱۱ ماه پیش بود که می خواستم بخش لاگین چندپر رو با نود جی اس بنویسم...خب اون موقع من مبتدی بودم و در حال یادگیری (هنوز هم هستم) به هر صورت با JWT و روشی توکن بیس ابداعی چیز بدی از آب در نیومد ولی همین چند وقت پیش مقاله ای رو توی سایت Medium دیدم که خیلی ساده و عالی این موضوع رو توضیح داده. من هم تصمیم گرفتم ترجمه اش بکنم تا هم خودم بهتر یاد بگیرم و این که شاید به درد کسای دیگه ای بخوره تا مثل من توی انبوهی از روش های پیچیده ی لاگین سردرگم نشن! از خط بعدی ترجمه ی بنده از متن اصلی مقاله مربوطه هست که می خوانید:

پیش نوشت۲: هم من و هم شمایی که داری می خونی احتمال زیاد برنامه نویسی می کنی و خب ... ! کد می خوایم ولی به هر حال هدف این نوشته نیست ولی می تونه فضایی فراهم بشه برای پرسش و پاسخ و جستجوی هدفمند


این مقاله نمی خواد که راهنمای کاملی برای OAuth 2.0 باشه بلکه تنها یک مقدمه ای برای نشان دادن مسیر های کاربران و این که چه مراحلی توی OAtuth 2 برای کاربر هست تا لاگین بکنه. ما می خواهیم با مشاهده و بررسی ۴ چارچوب در قالب مثال این موضوع رو به بررسی کنیم. و در نهایت هدف این نوشته این است که بتوانیم بهترین روش رو برای پروژه مون انتخاب کنیم.

واااای...کدومشو انتخاب کنم!؟
واااای...کدومشو انتخاب کنم!؟

آن چه که تا بحال من متوجه شدم و از بزرگان این حوزه فراگرفتم! به طور کلی می توانیم ۴ ورژن یا روش اجرای OAuth 2.0 را نام ببریم. البته بدین معنا نیست که باید همه ی این روش ها رو اجرا کنیم بلکه یکی از این موارد کافیست. نکته اینجاست که هدف مشترک این ۴ روش به درست آوردن access token و استفاده ی از آن برای دسترسی به اطلاعات و احراز هویت است. همین و بس... این ۴ روش به شرح زیر است:

  • کد مجوز (Authorization Code Grant): رشته کدی که به منظور صدور access token استفاده می شود. این کد موقعی که کاربر در فرانت لاگین می کند منتشر می شود و در مقابل access token در سمت سرور ایجاد می شود. در نتیجه کاربر با رمز عبور و کد حاصله احراز هویت می شود.
  • ضمنی (Implicit Grant): وقتی که کاربر لاگین می کند بالافاصله access token مربوطه ایجاد می شود.
  • اعتبار کلاینت (Client Credential Grant): access token در سمت سرور تنها برای احراز هویت کلاینت (نه کاربر) ایجاد می شود.
  • پسورد (Password Grant): access token بلافاصله تنها با یک request شامل اطلاعات لاگین کاربر (نام کاربری و رمز عبور و یا client id و client secret) اجرای این روش راحت تر است و در عین حال نواقصی هم دارد.
ملزومات روش های OAuth 2.0
ملزومات روش های OAuth 2.0

کد مجوز (Authorization Code Grant)

مراحل احراز هویت (لاگین) با کد مجوز و توضیحات آن در پایین
مراحل احراز هویت (لاگین) با کد مجوز و توضیحات آن در پایین

این مسیر احزار هویت کامل ترین و پیچیده ترین روش از انواع روش های OAuth2 است. مراحل لاگین در دو مرحله و با تضمین حد بالایی از امنیت انجام می شود.

عناصر کلیدی و تعاریف

  • اپلیکیشن کلاینت (Client App): در این مسیر عموما کلاینت یک web application است و باید شامل فرانت و بک اند باشد (بعدا می فهمیم چرا باید هر دو سمت باشد). بدین معنا که یه سایت خالی با Angular یا React یا ... نمی تواند این روش را اجرا کند. (البته می تواند از روش ضمنی (Implicit Grant) استفاده بکند که در ادامه گفته خواهد شد)
  • سرور احراز هویت (Authorization Server): بخشی که احراز هویت (authentication) و مجوز دهی (authorization) را اجرا می کند (یعنی درخواست های لاگین کاربر و احراز هویت کاربر و ایجاد توکن و اعتبار سنجی های امنیتی بر عهده ی این قسمت است)
  • سرور منابع (Resource Server): بخشی که اطلاعات و ... را در دسترس قرار می دهد و این می تواند همان REST API باشد. پس از به دریافت access token توسط فرانت قابل دسترسی و استفاده خواهد بود. یکی از تفاوت های بین سرور احراز هویت و سرور منابع در نوع کار آن هاست (سرور احراز هویت فقط درخواست های لاگین و توکن و ... رو هندل می کنه و در مقابل سرور منابع فقط مطالب و اطلاعات رو هندل می کنه). این تفکیک می تواند کمی گیج کننده به نظر برسد ولی اهمیت این تفکیک در کاری که انجام می دن خودش رونشون میده

شرح روش

بیاید به همراه جزییات نحوه ی کار این روش لاگین رو در ادامه بررسی کنیم:

۱- کاربر می خواهد لاگین کند

یک سناریوی کلاسیک برای این روش توسط کاربر در مرورگر اجرا می شه. کاربر روی دکمه ی «لاگین با 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]

پارامتر های ارسالی:

  • client_id: برای شناسایی و اطلاعات مربوط به اپلیکیشن کلاینت
  • redirect_uri: آدرسی که سرور احراز هویت در حین انتقال به آن کد احراز هویت را می فرستد (بعد از لاگین کاربر به همراه کد به این آدرس ریدایرکت می شود)
  • response_type: نوع پاسخ برگشتی سرور احراز هویت را مشخص می کند
  • scope: لیستی از بخش های اپلیکیشن که کاربر اجازه ی دسترسی به ان ها راخواهد داشت و کاربر درخواست لاگین را برای دسترسی به آن اطلاعات ارسال کرده است. (مثلا ایجاد مطلب یا خواندن پیام ها و ...) و این پارامتر برای سرور منابع جهت دسترسی دادن به اطلاعات لازم و مفید است. (تا در جاهایی که کاربر دسترسی ندارد ارور ۴۰۳ عدم دسرسی را بتواند ارسال کند)
  • state: پارامتری اختیاری که در هنگان برگشت به کلاینت بازگردانده می شود و برای بررسی اطلاعات استفاده می شود. (برای مثال می تواند سشن کاربر باشد )

۳- اعتبار سنجی درخواست لاگین (Request validation)

سرور احراز هویت بایستی تمامی پارامتر های لاگین را بررسی کند:

  • آیا کلاینتی با آی دی client_id وجود دارد؟ و آیا این کلاینت مجاز به ارسال request برای لاگین هست یا خیر؟
  • آیا کلاینت می تواند از redirect_uri استفاده کند؟ آیا با کلاینت مربوطه مرتبط است؟
  • آیا کلاینت اجازه ی درخواست برگشت با response_type را دارد؟
  • آیا کلاینت اجازه ی این استفاده از این توع احراز هویت را برای دسترسی به scope مربوطه دارد؟

پیشاپیش ذخیره ی کلاینت های در دسترس برای بررسی و هندل کردن این موارد ضروری است. و البته نگه داری و مدیریت اطلاعات کلاینت ها از حیطه ی وظایف OAuth خارج است.

۴- فرم لاگین

سرور احراز هویت فرم لاگین را به کاربر نشان می دهد و کاربر نام کاربری و رمز عبور خود را برای ورود به برنامه وارد می کند (مرحله ی ۵ در عکس)

بعد از بررسی اطلاعات توسط سرور احراز هویت (مرحله ی ۶ در عکس) اجازه ی دسترسی به scope مشخص شده را به کاربر می دهد و request خارج از اون scope تعیین شده مجاز نیست (چون ممکنه در استفاده از اپلیکیشن محدود شده باشه)

۵- انتقال (redirect) به کلاینت با کد مجوز authorization_code

سرور احراز هویت کد authorization code را ایجاد می کند و آن را روی redirect_url تعیین شده به سمت کلاینت بر می گرداند.

تمامی این مراحل در سمت کلاینت اتفاق می افتد (روی مرورگر یا اپلیکیشن موبایل) و در تمامی این مراحل کلاینت باید با بک اند در ارتباط باشد.

یه نظر من این موارد یکی از مهم ترین جنبه های انتخاب روش مناسب OAuth 2.0 برای پروژه هاست که یبا نیاز هامون منطبق بشه.

۸ , ۹- اعتبار سنجی کد مجوز (authorization code)

در اینجا کلاینت باید سرور احراز هویت را برای بررسی کد دریافت شده فراخوانی کند. برای این کار ارسال پارامتر های زیر لازم است:

  • authorization_code: برای بررسی
  • client_id: این پارامتر در کنار مورد بعدی جهت اطمینان از صحت کلاینت مورد استفاده قرار می گیرد و این که از دزدیده نشدن توکن مطمئن بشیم
  • client_secret: به عنوان رمز عبور کلاینت است و به صورت امن در سمت کلاینت ذخیره می شود

سرور احراز هویت تمامی اطلاعات بالا را از جهت صحت داشتن و همخوانی بررسی می کند. بررسی کد مربوطه باید از جهات کامل بودن و خطر دار نبودن و منتقضی نبودن و تعلق داشتن به کلاینت بررسی شود.

۱۰- کلاینت access_token را دریافت می کند

سرور احراز هویت access_token را ایجاد کی کند و آن را به سمت کلاینت بر می گرداند. انواع مختلفی برای ایجاد توکن وجود دارد. این ها می توانند تاریخ انقضا داشته باشند یا رفرش شوند. عموما همراه access_token اطلاعات زیر نیز به کلاینت برگردانده می شود:

  • token_type: نوع توکن
  • expires_in: تاریخ منقضی شدن توکن
  • refresh_token: توکنی دیگر برای ایجاد دوباره ی توکن اصلی هنکام انقضای آن

۱۱- کلاینت از access_token استفاده می کند

از این مرحله به بعد کلاینت access_token رو دریافت کرده و از آن برای دسترسی و شناسایی توسط سرور منابع (همون جایی که اطلاعات رو از دیتابیس می گیره و به کلاینت بر می گردونه) مورد استفاده قرار می گیرد.

سرور منابع یک بخشی از وب اپلیکیشن سمت سرور ماست که فرقی نمی کنه که از چه نوعی باشه می تونه RESRT API یا SOAP یا هر چیز دیگه ای باشه ... متد درخواست تغییر access_token بستگی به نوع منابع تون داره. متد متداول استفاده از REST API هست (در حال حاظر) با بهره گیری از HTTP header:

  • Authorization: شامل نوع توکن و خود توکن می شود

مثال (در هدر قرار گرفته است):

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ

۱۲ و ۱۳- اعتبار سنجی توکن

هر وقتی که سرور منابع درخواستی را دریافت می کند بایستی توکن از لحاظ اعتبار خود توکن و کلاینت آن اطمینان حاصل کند.

اعتبار سنجی توکن بسته به نوع ایجاد آن می تواند به روش های مختلفی صورت گیرد. این اعتبار سنجی می تواند در همان سرور منابع یا با فراخوانی سرور احراز هویت انجام شود.

به هر حال به معماری برنامه تون بستگی داره و در سمت کلاینت تفاوتی نشون داده نمی شه. اگر می خواید از روش OAuth برای احراز هویت کاربران استفاده کنید بهتره به نمونه های مربوط به نوع معماری برنامه تون مراجعه کنید تا انتخاب آگاهانه تر و کد های مناسب تری داشته باشید.

۱۴ و ۱۵- دسترسی و نمایش منابع اختصاصی

اطلاعات مخصوص با دسترسی محدود به کلاینت در هر بار اعتبار سنجی توکن توسط سرور منابع به کاربر نمایش داده خواهد شد.



ضمنی (Implicit Grant)

مراحل احراز هویت (لاگین) با روش ضمنی و توضیحات آن در پایین
مراحل احراز هویت (لاگین) با روش ضمنی و توضیحات آن در پایین

این روش مشابه روش قبلی (کد مجوز) است با این تفاوت که در روش ضمنی access_token بلافاصله پس از لاگین کاربر به سمت کلاینت ارسال می شود. از این روش در Single Page Applications ها مثل انگولار یا ری اکت یا ویو جی اس (نرم افزار هایی که از فریم ورک های جاوااسکریپت استفاده می کنن) استفاده می شود چرا که امکان محرمانه نگه داشتن client_secret وجود ندارد (که در روش اول که کد مجوز بود بحث شد)

اولبن تفاوت هنگام redirect شدن به سرور احراز هویت مشاهده می شود. مقدار پارامتر response_type از code به token تغییر یافته است. این بدین معناست که نوع پاسخ سرور بایستی بلافاصله access_token باشد به جای authorization_code.

در این روش مراحل کمتری نسبت به روش قبلی برای لاگین کاربر طی می شود اما در عین حال به علت طی شدن مراحل ثبت نام در مروگر امنیت کمتری نسبت به روش قبلی (کد توکن) دارد. مثلا token رد و بدل می شود در حالی که در روش کد مجوز به این صورت نیست و توکن بین درخواست های سرور ها منتقل می شود بنابراین دسترسی یا اختلال در آن بسیار دشوارتر است.


اعتبار کلاینت (Client Credential Grant)

مراحل احراز هویت (لاگین) با روش اعتبار کلاینت و توضیحات آن در پایین
مراحل احراز هویت (لاگین) با روش اعتبار کلاینت و توضیحات آن در پایین

تفاوت اصلی این روش در این است که کاربر در مراحل احراز هویت دخیل نیست و برنامه مستقیما خودش اقدام می کند.

این بدین معناست که نیازی به انجام کاری جلوی چشم کاربر ندارد بلکه همه ی مراحل فقط و فقط در پشت صحنه طی می شود.

این روش در سمت سرور اجرا می شود (نه در سمت کلاینت). redirect نداریم اما یک درخواست با متد POST با پارامتر های زیر ارسال می شود.

  • client_id
  • client_secret
  • grant_type: client_credentials
POST /token
&client_id=my-fancy-client-application &client_secret=xxxxxxx &grant_type=client_credentials

پاسخ دریافتی از سمت سرور access_token می تواند در درخواست های از سرور منابع مورد استفاده قرار گیرد.


پسورد (Password Grant)

مراحل احراز هویت (لاگین) با روش رمز عبور و توضیحات آن در پایین
مراحل احراز هویت (لاگین) با روش رمز عبور و توضیحات آن در پایین

بحث اصلی در این روش به نظر من اینه که کاربر در مرورگر (سمت کلاینت) نام کاربری و رمز عبور خود را وارد می کنه (نه در سرور احراز هویت). نکته ای لازمه در اینجا اشاره بشه اینه که اطلاعات محرمانه (credentials) به سرور احراز هویت تعلق داره نه به کلاینت.

این نکته بدین معناست که کاربر باید به طور کامل از جهت ارسال اطلاعات به سرور احراز هویت معتبر اطمینان حاصل کنه. برای فهم بهتر تصور کنید که برنامه ی شما قابلیت ثبت نام با اکانت فیسبوک را دارد این در حالی است که کاربر بایستی نام کاربری و رمز عبور اکانت فیسبوک خود را در برنامه شما وارد کنید. اگر شما جای این کاربر بودید چه می کردید؟ (خب ... ! اطلاعاتم رو وارد سایته می کردم!) در این وضعیت باید از جعلی نبودن سایت و عدم ذخیره یا تغییر در رمز عبور و نام کاربری اکانت فیسبوک خود توسط سایت اطمینان خاطر پیدا کنید.

اگر درست در خاطرم باشه اسپاتی فای همچن فیچری داشت کاربران مستقیما با اکانت فیسبوک شون تو اسپاتی فای لاگین می کردند.

در یک مرحله نام کاربری و رمز عبور توسط سمت کلاینت (فرانت) دریافت و به سمت سرور (بک اند) ارسال می شود. با استفاده از متد POST و پارامتر های زیر این درخواست انجام می شود:

  • grant_type: password
  • username of the user
  • password of the user
  • client_id
  • client_secret

مثال:

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

Photo by Fancycrave on Unsplash حالا وقتشه بریم تو کار - عکس توسط
Photo by Fancycrave on Unsplash حالا وقتشه بریم تو کار - عکس توسط

برای اجرای OAuth 2 به همکاری و توسعه در هر دو سمت کلاینت و سرور در زمینه های زیر نیاز است:

  • سمت کلاینت: اگر شما می خواهید از سرور احراز هویت استفاده کنید
  • سمت سرور: اگر شما می خواهید مکانیسم های تایید اعتبار رو مشخص کنید.

سمت کلاینت

در خاطر تون باشه که همیشه در تمامی این روش ها نیاز به رمز عبور کاربر هست و در نتیجه برای ذخیره ی این اطلاعات محرمانه نیاز به سرور احساس می شه. در مواردی که امکان سرور داشتن وجد نداره مثل اپلیکیشن های موبایل یا وب سایت های جاوااسکریپتی که شرایط متفاوتی دارند باید این مشکل رو با یک سرور اختصاصی برای این موضوع یا با روش های رمز نگاری حل کرد.

سمت سرور

فریم ورک ها و زبان های برنامه ویسی زیادی هستند که OAuth رو اجرا می کنن. این امر کارو در اجرای روش و اعتبار سنحی هایی که نیاز دارید (طرح کلی و کد های مربوط) راحت تر می کنه. اما من به ندرت راه حل های «هلو برو تو گلو !» (مثل آب خوردن) پیدا کردم.

یک چالش در اجرا می تواند پیکربندی و مدیریت کلاینت های متفاوت باشد که تنها با تصور کردن این موضوع می توانید به سرعت این نکته رو تصدیق کنید.

علاوه بر آن باید به scope و سطوح دسترسی مجوز های کاربران نیز توجه کنید. جای مدیریت این موضوع هر جایی می تونه باشه ولی ظریف تر این است که در مرحله ی حفاظت از منابع (در سرور منابع) اجرا شود.

نکته ی دیگر مزایای مدیریت token هاست که مانند یک دیتابیس عمل می کند و قابلیت ذخیره ی یک دوره ی کامل چرخه ی حیات کاربر را داراست.

  • release
  • renewal
  • expiration
  • revocation

بالاخره از کدام روش استفاده کنیم؟


انتخاب روش درست به عوامل متعددی بستگی داره. پاسخ به این سوالات می تواند به انتخاب درست شما منجر شود.

آیا شما می توانید client_secret را به صورت امن نگهداری کنید؟

بله: سوال بعدی

خیر: روش ضمنی IMPLICIT GRANT

آیا برنامه ی شما وب اپلیکیشن است؟

بله: سوال بعدی

خیر: روش کد مجوز CLIENT CREDENTIAL GRANT

آیا کاربر اعتماد کافی جهت ورود اطلاعات محرمانه ی کاربری خود را دارد؟

بله: روش پسورد PASSWORD GRANT

خیر: روش CLIENT CREDENTIAL GRANT

نتیجه گیری

امیدوارم این مقاله به دردتون خورده باشه و تبریک می گم که به آخرش رسیدید و این برای من بدین معناست که این نوشته به درد خیلیا خورده و تونسته کمکی هر چند کوچک به شمار بیاد.

منبع: An OAuth 2.0 introduction for beginners

پس نوشت۱: منم خیلی خوشحالم که بالاخره ترجمش تموم شد چون حدود یک ماه طول کشید (هفته ای یه روز وقت گذاشتم) و هر بخش رو هم که ببینید لحن متن متناسب با حال اون موقع من متفاوته! و البته می دونم کیفیت پایینی هم داره :o

پس نوشت۲: اخیرا یک آهنگی گیر آوردم که برام خیلی جذاب بود از لحاظ معنی و مفهومش. می گه که روزا می گذره و اینو همه هم می دونن ولی تو نصف عمرت رو می خوای از هر کسی یاد بگیری و در نهایت خدا تو رو به اون چیزی که تو رویاهات هست می رسونه... لینک soundcloud به این آهنگ Dream On - Aerosmith

موفق باشید ... فقط همین!



oauthتوکن
برنامه نویس node js و DevOps کار - دانش‌آموخته اقتصاد علاقه‌مند به کارآفرینی و استارتاپ ها - sadeghmohebbi.ir
شاید از این پست‌ها خوشتان بیاید