با OAuth2 آشنا شوید. قسمت چهارم

متن حاضر قسمت چهارم از سری مقالات آشنایی به پروتکل OAuth2 است، اگر سه قسمت قبلی رو مطالعه نکردید، قبل از مطالعه این قسمت، سری به سه لینک زیر بزنید.با OAuth2 آشنا شوید. قسمت اولبا OAuth2 آشنا شوید. قسمت دومبا OAuth2 آشنا شوید. قسمت سومدر دو قسمت ابتدایی درمورد نقش ها و کامپوننت های اصلی پروتکل OAuth2 صحبت کردیم و گفتیم که تعامل این کامپوننت ها با همدیگه منجر به ایجاد یک فرآیند OAuth میشه. در این قسمت قصد داریم کمی بیشتر در خصوص این تعامل بحث کنیم.پروتکل OAuth2 مبتنی بر پروتکل HTTP است. حتما میدونید که اساس پروتکل HTTP، درخواست (Request) و پاسخ (Response) است.تراکنش در HTTP Protocolخلاصه فرآیند پروتکل HTTP: در مرحله اول کلاینت درخواستی رو به سرور ارسال میکنه،‌ سرور درخواست رو پردازش و پاسخ رو تولید میکنه. درنهایت پاسخ رو از طریق Connection موجود برای کلاینت ارسال میکنه و Connection قطع میشه.با وجود سادگی تراکنش HTTP، پروتکل OAuth2 طی یک Request-Response ساده انجام نمیشه و شامل چندین درخواست-پاسخ است. جریان های OAuthهمانطور که در دو قسمت قبلی هم اشاره شد،‌ یک OAuth Transaction به دو بخش اصلی تقسیم میشه:دریافت Access Token از Authorization Serverاستفاده کلاینت از Access Token به دست آمده برای دسترسی به Protected Resourceبرای مرحله اول چندین Flow در پروتکل OAuth2 تعریف شده که هر کدوم روش متفاوتی برای گرفتن Access Token دارند. تفاوت اصلی این Flow ها که اصطلاحا به آن ها Authorization Grant Type هم گفته میشه در درخواست-پاسخ های آن هاست.به طور کلی چهار Authorization Grant Type وجود دارد:Implicit grant typeAuthorization grant typeClient credentials grant typeResource owner credentials grant typeجریان Implicit grant typeدر این Flow گرفتن Access Token از Authorization Server در یک مرحله انجام می شود.مراحل نمودار بالا را برای سناریوی اصلی تعریف می کنیم:1. در مرحله اول کاربر به کلاینت اعلام میکنه که قصد داره با سرویس مدنظر که اینجا اینستاگرام هست لاگین کنه.2. کلاینت درخواست زیر را به Authorization Endpoint اینستاگرام ارسال میکنه.GET https://api.instagram.com/oauth/authorize ?client_id={your-client-id}, &redirect_uri={your-redirect-uri}, &response_type=token, &scope={required-scopes-like-user_profile}توجه داشته باشید که:پارامتر response_type که نشان دهنده Grant Type است، روی token ست شده است نه codeو client_secret در این جریان هیچ نقشی ندارد. پس از ارسال درخواست، با توجه به وضعیت Authentication کاربر، کاربر به صفحه لاگین یا Consent ریدایرکت میشه. در این صفحه کاربر باید به سیستم لاگین و در نهایت رضایت خودش رو از دسترسی کلاینت به Scope های درخواست شده اعلام کنه.3. بعد از لاگین شدن و تایید درخواست توسط کاربر، Authorization Server اطلاعات کاربر که همون نام کاربری و رمزعبور هست رو بررسی میکنه و اگه اطلاعات معتبر بود، access_token رو میسازه و به کلاینت ریدایرکت میکنه.GET /your-redirect-uri#access_token={your_access_token}&token_type=Bearer4. کلاینت باید این access_token رو در جایی ذخیره کنه.5. از این مرحله به بعد هر زمانی که کلاینت قصد داشت به اینستاگرام درخواست بزنه (مثلا درخواست گرفتن اطلاعات کاربری) باید همراه با درخواستش access_token رو ارسال کنه.GET https://graph.instagram.com/me &access_token={user's-access-token}6. اینستاگرام اعتبار access_token دریافتی رو به کمک Authorization Server بررسی میکنه و اگه مشکلی وجود نداشت، درخواست کلاینت رو پردازش میکنه و جواب رو به کلاینت میفرسته.نکات زیر را در استفاده از Implicit Grant Type به خاطر بسپارید:این Flow برای Single Page Application ها استفاده میشه. بنابراین نیازی به استفاده از client_secret ندارید، چرا که تمامی ارتباطات Front Channel هستند و جایی برای مخفی نگه داشتن client_secret از مرورگر وجود ندارد.در جایی که Back-channel دارید بهتر است از Authorization Grant Type استفاده کنید.طبق استاندارد اصلی در Implicit Grant Type نمی توان Refresh Token دریافت کرد. البته این محدودیت در استاندارد تعریف شده و ممکن است سیستمی این محدودیت را در پیاده سازی درنظر نگیرد.درخواست دریافت توکن به Authorization Endpoint ارسال می شود.جریان Authorization grant typeدر این Flow گرفتن Access Token از Authorization Server در دو مرحله انجام میشه. در مرحله اول با ارسال درخواست به Authorization Endpoint کدی با نام Authorization Code دریافت میشه، درنهایت این کد به Token Endpoint فرستاده میشه و با Access Token مبادله میشه.مراحل نمودار بالا را برای سناریوی اصلی تعریف می کنیم:1. در مرحله اول کاربر به کلاینت اعلام میکنه که قصد داره با سرویس مدنظر که اینجا اینستاگرام هست لاگین کنه.2. کلاینت درخواست زیر را به Authorization Endpoint اینستاگرام ارسال میکنه.GET https://api.instagram.com/oauth/authorize ?client_id={your-client-id}, &redirect_uri={your-redirect-uri}, &response_type=code, &scope={required-scopes-like-user_profile}توجه داشته باشید که:پارامتر response_type که نشان دهنده Grant Type است، روی code ست شده است نه tokenو client_secret در مرحله اول نقشی ندارد. پس از ارسال درخواست، با توجه به وضعیت Authentication کاربر، کاربر به صفحه لاگین یا Consent ریدایرکت میشه. در این صفحه کاربر باید به سیستم لاگین و در نهایت رضایت خودش رو از دسترسی کلاینت به Scope های درخواست شده اعلام کنه.3. بعد از لاگین شدن و تایید درخواست توسط کاربر، Authorization Server اطلاعات کاربر که همون نام کاربری و رمزعبور هست رو بررسی میکنه و اگه اطلاعات معتبر بود، authorization_code رو میسازه و به کلاینت ریدایرکت میکنه.GET /your-redirect-uri#code={your-authorization-code}&token_type=Bearer4. در این مرحله کلاینت authorization_code رو از URL اکسترکت میکنه و درخواست تبادل این کد با access_token رو ارسال میکنه.POST https://api.instagram.com/oauth/token grant_type=authorization_code& client_secret={your-client-secret} redirect_uri={your-redirect-uri} &code={your-authorization-code}5. سرور Authorization اطلاعات ارسال شده مثل redirect_uri و client_secret رو بررسی میکنه و درصورت صحت برای کاربر access_token رو تولید کرده و در پاسخ ارسال میکنه.HTTP 200 OK { &quotaccess_token&quot: &quot{users-access-token}&quot, &quottoken_type&quot: &quotBearer&quot }کلاینت باید این access_token رو در جایی ذخیره کنه.5. از این مرحله به بعد هر زمانی که کلاینت قصد داشت به اینستاگرام درخواست بزنه (مثلا درخواست گرفتن اطلاعات کاربری) باید همراه با درخواستش access_token رو ارسال کنه.GET https://graph.instagram.com/me &access_token={user's-access-token}6. اینستاگرام اعتبار access_token دریافتی رو به کمک Authorization Server بررسی میکنه و اگه مشکلی وجود نداشت، درخواست کلاینت رو پردازش میکنه و جواب رو به کلاینت میفرسته.نکات زیر را در استفاده از Authorization grant type به خاطر بسپارید:تنها زمانی که Back Channel دارید میتوانید از این Flow استفاده کنید. درنتیجه برای SPA اصلا مناسب نیست.طبق استاندارد در این Flow میتوان Refresh Token دریافت کرد.جریان Client credentials grant typeتا به حال هر زمان که بحث از OAuth2 شد، صحبت از کاربر به میان اومد. گفتیم که هدف اصلی OAuth2 اینه که کاربر مجوز دسترسی به اطلاعات Protected خودش رو به یک کلاینت اعطا کند. حال فرض کنید اصلا کاربری درکار نباشد و دو سیستم قرار است بدون هیچ کاربری با همدیگر ارتباط برقرار کنند، در این حالت از جریان Client Credential استفاده می شود.1. در مرحله اول کلاینت درخواست خود را به Token Endpoint ارسال میکند.POST https://api.instagram.com/oauth/token grant_type=client_credentials &client_id={your-client-id} &client_secret={your-client-secret} &scope={required-scopes}2. سیستم Authorization پس از دریافت درخواست، ابتدا اطلاعات کلاینت رو بررسی میکند و اگر کلاینت معتبر بود access_token کلاینت رو تولید و در Response به کلاینت ارسال میکند.HTTP 200 OK { &quotaccess_token&quot: &quot{client's-access-token}&quot, &quotscope&quot: &quot{requested-scopes}&quot, &quottoken_type&quot: &quotBearer&quot }4. کلاینت باید این access_token رو در جایی ذخیره کنه.5. از این مرحله به بعد هر زمانی که کلاینت قصد داشت به Protected Resource درخواست بده باید همراه با درخواستش access_token رو ارسال کنه.GET https://graph.instagram.com/explore &access_token={client's-access-token}6. اینستاگرام اعتبار access_token دریافتی رو به کمک Authorization Server بررسی میکنه و اگه مشکلی وجود نداشت، درخواست کلاینت رو پردازش میکنه و جواب رو به کلاینت میفرسته.نکات زیر را در استفاده از Client credentials grant type درنظر بگیرید:هر دو مقدار client_id و client_secret باید در درخواست فرستاده شوند.درخواست دریافت توکن به Token Endpoint ارسال می شود.در این Flow کاربر هیچ نقشی ندارد. به عبارت دیگر تعامل OAuth2 بین کلاینت شما و سرویس اصلی در حال انجام است. مثالی از کاربرد Client credential grant typeفرض کنید سیستمی برای پردازش وضعیت آب و هوایی دنیا دارید. در این سیستم وضعیت آب و هوای تمام شهرها و کشورها پردازش میشه و اطلاعات مفیدی مثل پیش بینی وضعیت آب و هوایی به دست میاد. شما قصد دارید سیستم تون رو در اختیار کلاینت های دیگه بزارید و از این کار درامدزایی کنید. یکی از روش های پیاده سازی استفاده از این Grant type است. به این صورت که شما برای هر کلاینتی که میخواهد از سرویس شما استفاده کند یک client_id و client_secret میسازید و کلاینت ها ابتدا با استفاده از این دو مقدار به سیستم شما Authenticate می شوند و سپس می توانند از API شما استفاده کنند.به طور خلاصه میتوان گفت که زمانی که ارتباط سرویس به سرویس دارید یکی از راه های پیاده سازی، Client credential grant type است.جریان Resource owner credential grant typeدر این Flow کلاینت اطلاعات کاربری اینستاگرام رو از کاربر درخواست میکنه و خودش مستقیم به اینستاگرام درخواست لاگینش رو میفرسته و توکن رو دریافت میکنه.1. کاربر ابتدا اطلاعات کاربری خود را در اختیار کلاینت قرار می دهد.2.کلاینت درخواست خود را به Token Endpoint ارسال میکند.POST /token grant_type=password &client_id={client-id} &client_secret={client-secret} &scope={required-scopes} &username={username} &password={password}همانطور که می بینید اطلاعات کاربر در درخواست به صورت مستقیم به Authorization Server ارسال می شود. 3. در این مرحله Authorization Server اطلاعات کلاینت و کاربر رو بررسی میکنه و اگه اطلاعات معتبر بود، access_token رو میسازه و در پاسخ به کلاینت ارسال میکنه.4. کلاینت باید این access_token رو در جایی ذخیره کنه.5. از این مرحله به بعد هر زمانی که کلاینت قصد داشت به اینستاگرام درخواست بزنه (مثلا درخواست گرفتن اطلاعات کاربری) باید همراه با درخواستش access_token رو ارسال کنه.6. اینستاگرام اعتبار access_token دریافتی رو به کمک Authorization Server بررسی میکنه و اگه مشکلی وجود نداشت، درخواست کلاینت رو پردازش میکنه و جواب رو به کلاینت میفرسته.نکات زیر را در استفاده از Resource owner credential grant type درنظر بگیرید:درخواست توکن به Token Endpoint ارسال می شود.به هیچ وجه روش پیشنهاد شده ای نیست، به گونه ای که حتی بعضی از سرویس ها این روش رو به کل پیاده سازی نکردند.اگه قسمت اول رو با دقت مطالعه کرده باشید، این جریان همان "راه حل دوم" است. درست است که گفتیم راه حل های قبل از OAuth2 همگی دارای معایبی هستند، اما این جریان برای زمان هایی که نمی خواهیم کاربر به طور مستقیم با Authorization Server در ارتباط باشد مناسب است. هر چند که طبق استاندارد تعریف شده بهتر است تنها در شرایط خاص از این جریان استفاده کرد.