در این مقاله جامع آموزشی قصد داریم به مبحث بسیار مهمی تحت عنوان OAuth2 یا احراز هویت به روش حرفهای و کارآمد برای زبان برنامه نویسی بپردازیم.
فریم ورک احزار هویت OAuth 2.0 به عنوان یک بستهی کاربردی جهت محدود کردن دسترسی به سرویسهای HTTP ایجاد شده است.
در مدلهای قدیمی احراز هویت کلاینت-سرور، درخواستهای کاربران یا کلاینتها به منابع محافظتشده توسط مجوزهای کلاینت که از طرف سرور تعیین شده بود، مدیریت و احراز هویت میشد. حال برای دسترسی نرمافزارها یا پکیجهای دیگر در وب اپلیکیشن شما، به منابع محدود شده، مجوزهای کاربر یا کلاینت با این نرم افزارها و پکیج ها به اشتراک گذاشته میشود. این روش مشکلاتی را به وجود میآورد که عبارتند از:
حال فریم ورک OAuth این موضوع را بدین صورت حل کرد که یک لایه احراز هویت (Authorization Layer) ایجاد کرده و نقش کلاینت (کلاینت میتواند کاربر یا مرورگر یا یک نرمافزار باشد) را از مجوز دسترسی آن جدا کند. در نتیجه به جای استفاده از مجوزهای دسترسی برای منابع محافظت شده میتوان از اکسس توکن (access_token) استفاده کرد که این access token به صورت یک رشته حاوی حروف و اعداد ایجاد میشود و دارای زمان انقضاء، اسکوپ (یا محدوده) و سایر ویژگیها است. access token ها به هر یک از نرمافزارها یا پکیجها یا کاربران توسط یک سرور احراز هویت اختصاص داده میشوند. حال کاربر یا کلاینت از این access token برای دسترسی به منابع و بخشهای مختلف استفاده میکند. برای مثال یک کاربر میتواند به تصاویر ذخیره شده اش در یک منبع دسترسی داشته باشد بدون آنکه اطلاعات یوزرنیم و پسوردش را وارد کند.
OAuth 2 یک فریم ورک یا پروتکل صدور مجور (authorization) است که به برنامه ها اجازه می دهد که بدون داشتن رمز عبور و اطلاعات حساس، از طریق پروتکل HTTP به منابع مشخصی مثل اطلاعات کاربران دسترسی داشته باشند. چنین مواردی را حتما در API وب سایت هایی مانند GitHub دیده اید. در واقع شما با استفاده از OAuth 2.0 می توانید اطلاعات یک کاربر در یک سایت دیگر را بخوانید (البته به صورت محدود) بدون اینکه به رمز عبور آن کاربر دسترسی داشته باشید.
OAuth 2.0 چهار «نقش» یا role تعریف می کند:
برای اینکه بهتر بدانیم OAuth 2.0 چیست باید با این چهار نقش آشنا باشیم.
به صورت کلی OAuth چهار نقش را معرفی میکند:
این نقش همان user یا کاربر است و نقشی است که دارای منابع (فایل ها یا اطلاعات) مشخص است. user در تعریف اصلی همان فردی است که به یک application (برنامه) اجازه دسترسی به اطلاعاتش را می دهد (از طریق یک token). این دسترسی بنابر سطح دسترسی مشخص شده توسط کاربر یا scope دسترسی محدود خواهد بود. مثلا آیا برنامه اجازه انجام دستورات read و Write را دارد؟
کلاینت همان برنامه یا application ای است که می خواهد با استفاده از این پروتکل به سرور متصل شده و به اطلاعات کاربر برسد. به طور مثال در دنیای وب، کلاینت معمولا همان مرورگر کاربر است.
از آنجایی که در فضای وب معمولا هر دو عملیات احراز هویت و نگهداری از منابع توسط یک سرور یا یک مجموعه سرور انجام می شود این دو نقش را ترکیب کرده ایم و در کل مقاله با عنوان API به آن اشاره می کنیم چرا که این نقش در واقع همان API می باشد.
اگر بخواهیم برای این چهار نقش یک دیاگرام مناسب ترسیم کنیم، خواهیم داشت:
همانطور که در دیاگرام فوق ملاحظه میکنید، البته این تصویر یک جریان کلی برای مفهوم OAuth است و در grant type های متخلف متفاوت خواهد بود (در ادامه در مورد انواع این grant ها توضیح خواهیم داد) بنابراین از آن فقط در جهت درک نحوه کلی و مراحل کار OAuth استفاده کنید. این مراحل به ترتیب عبارت اند از:
البته روند اجرای مراحل بالا بر اساس نوع دسترسی که به شما داده شده است متفاوت خواهد بود اما مفهوم کلی OAuth در همین شش مرحله خلاصه می شود. توجه داشته باشید که چهار مرحله اول برای دریافت مفهومی به نام authorization grant (مجوز دسترسی) انجام می شوند.
تمامی مراحلی که تا اینجای کار گفته شد مربوط به روند کاری ارتباط با OAuth بودند اما قبل از اینکه بخواهید با OAuth کار کنید باید برنامه خود را در سرورهای هدف ثبت کرده باشید. مثلا اگر می خواهید از API گیت هاب استفاده کنید دو گزینه دارید:
عملیات ثبت برنامه معمولا توسط یک فرم ساده در وب سایت مورد نظر شما انجام می شود و کار خاصی ندارد. در این فرم اطلاعاتی مثل نام برنامه و آدرس وب سایت شما از شما پرسیده می شود. همچنین مقداری تحت عنوان Redirect URI یا Callback URL نیز از شما خواسته می شود. این مقدار همان آدرسی است که کاربر به آن redirect شده یا پاسخ درخواست به API برایتان ارسال می شود. به طور مثال کسی که با دکمه sign up with google در وب سایت شما ثبت نام می کند پس از کلیک روی این دکمه به گوگل می رود و پس از ورود به حساب کاربری خود به صفحه ای از سایت شما برگردانده می شود که آدرس آن به شما بستگی دارد و همان Redirect URI است. به زبان ساده تر این مقدار همان قسمتی از سایت یا برنامه شما است که مسئول مدیریت این نوع درخواست ها می باشد.
به طور مثال برای API گیت هاب، این فرم درون حساب کاربری، قسمت dashboard و قسمت توسعه دهندگان قرار دارد. در مجموعه «پروژه های مدرن جاوا اسکریپت» پروژه ای ساده برای کار با API گیت هاب منتشر شده است و در آنجا به صورت عملی کار را مشاهده می کنید بنابراین به این قسمت سری بزنید.
قبل از مقداردهی اولیه پروتکل OAuth، کلاینت توسط سرور احراز هویت ثبت میشود. بدین معنی که ثبت این کلاینت درون یک اسکوپ یا محیط محدود صورت میپذیرد. برای ثبت کلاینت، نوع کلاینت و شناسهی کلاینت حائز اهمیت است. بنابراین به توضیح این دو مورد خواهیم پرداخت:
زمانی که برنامه خود را در وب سایت مورد نظر ثبت کنید، سرویس مورد نظر (مثلا گیت هاب) دسته ای از اطلاعات به نام client credentials را به شما می دهد. این داده ها شامل دو قسمت مهم است:
فریم ورک OAuth دو نوع کلاینت در اختیار دارد که بر اساس توانایی هر یک میتوان از آنها استفاده کرد. این توانایی ها برای تعیین امنیت احراز هویت در سرور احراز هویت اعمال میشوند:
confidential: این نوع کلاینت به صورت محرمانه میباشد و مجوزها را به صورت محرمانه نگه میدارد. به عبارت دیگر کلاینت پیاده سازی شده روی یک سرور امن با محدود کردن دسترسی به مجوزهای آن کلاینت امکان پذیر خواهد بود. یعنی مجوزهای یک کلاینت را با دسترسی محدود در اختیار سرور قرار میدهیم.
public: این نوع کلاینت به صورت عمومی در اختیار سرور و سایر اپلیکیشن هاست.
در صورتیکه نوع کلاینت به صورت confidential یا محرمانه تعریف شود، کلاینت و سرور احراز هویت یک متد احراز هویت مناسب را برای برقراری امنیت در سرور ایجاد میکنند. در حالت کلی یک متد به عنوان معیار واحد در نظر گرفته میشود که تحت عنوان Client Password معرفی خواهد شد.
کلاینتها همگی به صورت یک پسورد مشخص بر روی سرور احراز هویت ذخیره میشوند. مفهوم Password بدین صورت است که شناسهی کلاینت به صورت یک کد رمزگذاری شده شامل مجموعه ای از رشته ها درون پایگاه داده ذخیره میشود.
Access Token ها مجوزهایی هستند که برای دسترسی به منابع محافظت شده مورد استفاده قرار میگیرند. یک Access Token در واقع شامل مجموعهای از رشتهها و اعداد است که توسط کلاینت مورد استفاده قرار میگیرند و به عنوان پاسپورد یا برگهی ورود کاربر یا کلاینت محسوب میشود. هر Access Token دارای یک طول عمر، مقدار و سایر ویژگیهای مشخص است.
Refresh Token ها مجوزهایی هستند که برای تعیین Access Token ها مورد استفاده قرار میگیرند. Refresh Token ها در واقع توسط سرور احراز هویت برای کاربران (کلاینتها) صادر میشوند و معمولا برای ایجاد Access Token هایی که طول عمر آنها به اتمام رسیده است مورد استفاده قرار میگیرد.
می دانیم که با استفاده از Client ID و Client Secret می توانیم به منابع مشخصی دسترسی پیدا کنیم اما نحوه این دسترسی و سطح دسترسی ها بستگی به نوع authorization grant دارد. قبل از مطالعه این مقاله باید با API ها و اصطلاحات آن ها آشنایی داشته باشید. برای شروع می توانید مقاله «آشنایی با REST API» را مطالعه کنید.
یک مجوز اعطا شده عبارت است از مجوزی که توسط کاربر یا یک شخص برای دسترسی به فایلهای شخصیاش و دستیابی به یک اکسس توکن (access_token) اعطا میشود. (به عنوان مثال یک کاربر فیس بوک اجازه میدهد که نرم افزار گوگل به حساب کاربر او متصل شود). این اعطای مجوز دارای ۴ نوع است که شامل موارد زیر میباشد:
Authorization Code: شایع ترین نوع بوده و با برنامه های server-side کار می کند. این نوع، توسط سرور احزار هویت به عنوان یک میانجی بین کاربر (کلاینت) و نرم افزاری که کاربری در آن عضو است، تعیین میشود. در واقع در این مدل به جای ارسال درخواست احراز هویت از resource owner، کاربر یا کلاینت به صورت مستقیم، resource owner را به سرور احراز هویت متصل میکند.
Implicit: این نوع در واقع ساده شده روش Authorization code است. در این مدل به جای صادر کردن مجوز برای یک کاربر یا کلاینت، کلاینت به صورت مستقیم access token را بدست میآورد. به عبارت دیگر برای کار با دستگاه های موبایل و برنامه های وب استفاده می شود (برنامه هایی که در دستگاه کاربر اجرا می شوند).
Resource Owner Password Credentials: در این نوع اطلاعات کاربری مانند username و password به صورت مستقیم برای دستیابی به access token در اختیار سرور قرار میگیرد. از این روش معمولا زمانی استفاده میکنند که سیستم کاربری و احراز هویت و درخواست ها درون یک سرور انجام گیرد. همچنین برای برنامه های مطمئن و ایمن استفاده می شود. به طور مثال برنامه هایی که توسط خود سرویس و کمپانی ساخته شده اند و هویت آن ها 100 در 100 مشخص است.
Client Credentials: از این نوع زمانی استفاده میشود که بخواهیم احراز هویت را برای یک اسکوپ یا منبع مشخصی تعیین کنیم. معمولا توسط API برنامه ها استفاده می شود.
تصویر زیر ویژگی های هرکدام را نمایش می دهد:
متوجه هستم که این چهار حالت برای شما گنگ می باشند بنابراین بیایید هر کدام را جداگانه بررسی کنیم.
این grant type (نوع دسترسی) رایج ترین نوع grant type می باشد چرا که با برنامه های سمت سرور کار کرده و در آن Client Secret همیشه مخفی می ماند. در چنین نوعی از دسترسی برنامه شما باید توانایی کار کردن با user agent (مثلا مرورگر کاربر) را داشته باشد و کدهای دسترسی را که به user agent ارسال می شود، دریافت کند. جریان کاری این نوع از دسترسی در تصویر زیر آمده است:
مراحل نمایش داده شده در تصویر بالا به شرح زیر است:
قدم اول: لینک Authorization Code
در قدم اول ما لینکی به کاربر می دهیم که ساختار زیر را دارد:
https://cloud.digitalocean.com/v1/oauth/authorize?response_type=code&client_id=CLIENT_ID&redirect_uri=CALLBACK_URL&scope=read
من ساختار این لینک را برایتان می شکنم:
client_id=client_id
: همان client ID شما است و از طریق آن برنامه شما شناسایی می شود بنابراین باید به جای client_id دوم، مقدار واقعی client_id خود را قرار دهید.redirect_uri=CALLBACK_URL
: زمانی که کد دسترسی تایید شود، کاربر به این صفحه از وب سایت یا برنامه شما منتقل خواهد شد. اگر برنامه شما یک ربات است، پاسخ دریافتی از سرور به این قسمت ارسال می شود.response_type=code
: این قسمت مشخص می کند که نوع authorization grant شما چیست. ما در اینجا code را نوشته ایم، یعنی از نوع دسترسی اول که code است.scope=read
: سطح دسترسی (نه نوع دسترسی) را مشخص می کند. read یعنی توانایی خواندن اطلاعات اما اگر write را هم اضافه می کردیم، توانایی نوشتن و ویرایش اطلاعات را به برنامه می دادیم.این ساختار خاص مربوط به نوع اول از دسترسی های OAuth است و در قدم اول اتفاق می افتد. شما می توانید این لینک را به صورت یک دکمه «ثبت نام با گوگل» یا sign up with google در نظر بگیرید که امروزه در بسیاری از سایت ها وجود دارد.
قدم دوم: تایید دسترسی توسط کاربر
زمانی که کاربر روی لینک کلیک کند، باید ابتدا وارد حساب خود در سرویس شوند. مثلا در همان دکمه «ثبت نام با گوگل» کاربر باید وارد حساب گوگل خود شود مگر اینکه از قبل sing in بوده باشند. سپس یک صفحه برای کاربر نمایش داده می شود و از او می خواهد درخواست دسترسی یا تایید را رد کند:
همانطور که می بینید یکی از تصاویر بالا مربوط به گوگل و تصویر دیگر مربوط به DigitalOcean است. مثلا در اسکرین شات بالا از DigitalOcean برنامه ای به نام Thedropletbook App می خواهد به اطلاعات حساب ما دسترسی داشته باشد (از نوع read). آدرس ایمیل صاحب حساب هم manicas@digitalocean.com می باشد.
قدم سوم: دریافت Authorization Code توسط برنامه
در مثال بالا اگر کاربر روی Authorize Application یا Allow کلیک کند، به صفحه مورد نظر در برنامه ما redirect می شود. اگر یادتان باشد آدرس این صفحه را هنگام ثبت برنامه مشخص کردیم و در مورد آن توضیح دادم (به قسمت قبل مراجعه کنید). مثلا اگر برنامه خود را dropletbook.com فرض کنیم، آدرس redirect کاربر چیزی شبیه به آدرس زیر می شود:
https://dropletbook.com/callback?code=AUTHORIZATION_CODE
قدم چهارم: درخواست Access Token توسط برنامه
در این مرحله برنامه ما درخواست توکن دسترسی (access token) را به API ارسال می کند. این درخواست معمولا شامل authorization code (در مرحله قبل دریافت کردیم) و جزئیات احراز هویت (مثل client id و Client secret) می شود که به end-point آن API ارسال می شوند. به طور مثال درخواست زیر که از نوع POST است به سرور DigitalOcean ارسال شده است:
https://cloud.digitalocean.com/v1/oauth/token?client_id=CLIENT_ID&client_secret=CLIENT_SECRET&grant_type=authorization_code&code=AUTHORIZATION_CODE&redirect_uri=CALLBACK_URL
قدم پنجم: دریافت Access Token توسط برنامه
اگر درخواست ارسالی معتبر باشد، API پاسخ خود را به همراه access token به برنامه ما ارسال می کند. در برخی موارد یک refresh token نیز به همراه آن ارسال می شود. تمام پاسخ سرور چیزی شبیه به شیء JSON زیر است:
{"access_token":"ACCESS_TOKEN","token_type":"bearer","expires_in":2592000,"refresh_token":"REFRESH_TOKEN","scope":"read","uid":100101,"info":{"name":"Mark E. Mark","email":"mark@thefunkybunch.com"}}
حالا درخواست تکمیل شده و کار ما تمام شده است! همانطور که می بینید برنامه ما به اطلاعات کاربر دسترسی دارد (البته در سطح read) تا زمانی که token منقضی شود (قسمت expiers_in در پاسخ بالا). زمانی که توکن ما منقضی می شود می توانیم با استفاده از refresh_token یک توکن جدید درخواست کنیم.
نوع اول را بررسی کردیم و حالا نوبت به بررسی نوع دوم یعنی implicit grant و انواع باقی مانده دیگر است. این نوع از grant مخصوص نرم افزارهای موبایلی و برنامه های تحت وب است (یعنی برنامه هایی که در مرورگر اجرا می شوند). در چنین حالتی، برخلاف نوع اول یا code grant، ممکن است client secret در معرض دید عموم باشد و محفوظ ماندن آن ضمانت شده نیست. اساس این نوع Grant مانند grant نوع اول روی redirect شدن است؛ توکن دسترسی در این حالت به user-agent داده می شود تا user-agent آن را به برنامه پاس بدهد، به همین خاطر ممکن است در معرض دید خود کاربر و دیگر برنامه های سیستم باشد. همچنین باید توجه کرد که در این نوع از grant هویت برنامه احراز نمی شود و تمرکز روی URI خواهد بود و refresh token ها را نیز نخواهیم داشت.
جریان کاری این grant را در تصویر زیر برایتان آورده ایم:
ابتدا از کاربر خواسته می شود که به برنامه اجازه دسترسی دهد، سپس سرور مربوطه توکن دسترسی را برای user-agent ارسال می کند و user-agent نیز آن را به برنامه می فرستد. بگذارید این مراحل را تک به تک بررسی کنیم.
قدم اول: لینک صدور مجوز (authorization)
در implicit gant ها معمولا به کاربر لینکی داده می شود که برای فرآیند صدور مجوز است. این لینک باعث ایجاد یک درخواست برای دریافت یک توکن از API می شود. تفاوت این لینک با لینکِ authorization code (نوع اول) در این است که به جای درخواست برای کُد، درخواست خود را برای دریافت یک توکن ارسال می کنیم. در لینک زیر توجه کنید که response type از نوع token است نه code:
https://cloud.digitalocean.com/v1/oauth/authorize?response_type=token&client_id=CLIENT_ID&redirect_uri=CALLBACK_URL&scope=read
قدم دوم: تایید دسترسی توسط کاربر
زمانی که کاربر روی این لینک کلیک می کند باید ابتدا وارد سرویس و حساب کاربری خود شود. سپس دقیقا مثل نوع اول از grant ها از کاربر خواسته می شود که دسترسی برنامه را تایید (کلماتی مثل authorize یا allow) و یا رد (deny) کند:
در تصویر بالا مشخص است که برنامه ای به نام Thedropletbook App درخواست read (خواندن اطلاعات) را برای حساب کاربری manicas@digitalocean.com داده است.
قدم سوم: دریافت توکن و URI توسط user-agent
اگر کاربر در مرحله قبل به برنامه اجازه دسترسی بدهد، سرور کاربر را به همان URI (آدرس redirect که هنگام ثبت برنامه مشخص کردیم) redirect می کند که قسمتی از آن حاوی توکن دسترسی است. مثلا آدرسی شبیه به آدرس زیر:
https://dropletbook.com/callback#token=ACCESS_TOKEN
قدم چهارم: user-agent به آدرس URI می رود
زمانی که آدرس URI به همراه توکن دسترسی (access token) برای user-agent ارسال شد، user-agent به این آدرس می رود اما توکن دسترسی را نگه می دارد.
قدم پنجم: توکن دسترسی به اسکریپت برنامه ارسال می شود
برنامه ما صفحه وب ای را برمی گرداند که حاوی اسکریپت خاصی با توانایی خارج کردن توکن دسترسی از URI می باشد.
قدم ششم: توکن دسترسی به برنامه می رسد
User-agent (مثلا مرورگر) اسکریپت ذکر شده را اجرا می کند و توکن استخراج شده را به برنامه می دهد. حالا برنامه ما مجوز دسترسی را گرفته است و تا زمانی که توکن منقضی نشده است می تواند از این توکن برای خواندن اطلاعات کاربر استفاده کند.
تایپ resource owner password credentials
تایپ grant بعدی ما resource owner password credentials است. در این حالت کاربر اطلاعات نام کاربری و رمز عبور خود را مستقیما در برنامه وارد می کند و برنامه از این طریق یک توکن دسترسی دریافت می کند. شما باید تا حد ممکن از این نوع Grant دوری کنید و فقط زمانی از آن استفاده شود که هیچ نوع دیگری از grant موجود نباشد. همچنین فقط در شرایطی از آن استفاده می شود که کاربر اطمینان کامل به برنامه داشته باشد و هویت سازندگان آن مشخص باشد (مثلا هنگامی که برنامه توسط خود سرویس ساخته شده باشد – مثل برنامه github برای ویندوز که توسط خود github ساخته شده است).
زمانی که شما رمز عبور و حساب کاربری خود را وارد برنامه کنید یک درخواست POST به شکل زیر به سرور ارسال می شود:
https://oauth.example.com/token?grant_type=password&username=USERNAME&password=PASSWORD&client_id=CLIENT_ID
اگر اطلاعات وارد شده در آدرس بالا صحیح باشد، سرور یک توکن دسترسی برای برنامه ارسال می کند.
تایپ client credentials
این نوع از grant برای دسترسی برنامه به منابع و اطلاعات خود برنامه است! مثلا هنگامی که برنامه بخواهد توضیحات خود یا redirect URI خود را تغییر دهد ( اگر یادتان باشد این موارد در هنگام ثبت برنامه ذخیره می شدند). در این حالت برنامه ما client id و client secret خود را به سرور ارسال می کند تا توکن دسترسی دریافت کند. درخواست POST در این حالت چیزی شبیه به درخواست زیر می شود:
https://oauth.example.com/token?grant_type=client_credentials&client_id=CLIENT_ID&client_secret=CLIENT_SECRET
بدین صورت سرور یک توکن دسترسی را برای برنامه ارسال می کند تا بتواند اطلاعات خودش را تغییر دهد.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.