شما به احتمال زیاد از وبسایتها یا اپلیکیشنهای موبایلی استفاده میکنید که به جای شما در وبسایتها یا سرویسهای دیگر کاری انجام میدهند. به طور مثال اگر اکانت توییتر دارید، احتمالاً از یک کلاینت توییتر روی دسکتاپ یا موبایلتان استفاده کردهاید (یا مثل من چندتایی را امتحان کرده و از هیچ کدام راضی نبودهاید) یا شاید آهنگهایی که گوش میدهید توسط Scrobbler در اکانت last.fm شما ثبت میشوند. یا از طریق اپلیکیشن موبایل وردپرس فعالیتهای وبلاگتان را دنبال میکنید. در همهی این موارد شما از استانداردی به نام OAuth استفاده کردهاید.
تفاوت OAuth و OpenID
با اینکه این دو استاندارد در نگاه اول شبیه هم هستند اما تفاوتهای زیادی دارند و در واقع کارهای مختلفی انجام میدهند. OpenID به این درد میخورد که به وسیلهی یک اکانت در چندین سایت مختلف ثبتنام کنید و به این ترتیب دردسر به خاطر سپردن نامهای کاربری و پسوردهای مختلف را نداشته باشید. اما به وسیله OAuth شما به یک اپلیکیشن یا وبسایت (مصرفکننده) اجازه میدهید به جای شما در یک سرویس دیگر (ارائهدهنده) کاری انجام دهند. درواقع شما در هنگام استفاده از OAuth باید در سرویس ارائهدهنده لاگین کنید. یعنی نام کاربری و پسورد خود را در آنجا وارد کنید و سپس اجازهی دسترسی به مصرفکننده را بدهید. اینکه ارائهدهنده شما را با چه وسیلهی لاگین میکند ربطی به OAuth ندارد. حتی میتوانید برای لاگین کردن از OpenID استفاده کنید.
کاربرد OAuth
OAuth به این درد میخورد که شما بدون اینکه نام کاربری و پسوردتان را با مصرفکننده به اشتراک بگذارید به او اجازه دهید به جای شما فعالیت کند. شما نام کاربری و پسورد را در سایت ارائهدهنده وارد میکنید و وارد حساب کاربری خود میشوید، در آنجا ارائهدهنده به شما اعلام میکند که مصرفکننده قصد انجام چه کارهایی را دارد و از شما برای صدور مجوزهای لازم اجازه میگیرد. هر زمان هم که نیاز داشتید میتوانید دسترسی مصرفکننده را از طریق سایت ارائهدهنده مسدود کنید.
مزیت این روش وقتی مشخصتر میشود که چندین مصرفکننده بخواهند از طرف شما به یک ارائهدهنده متصل شوند. اگر روزی بخواهید دسترسی تمام مصرفکنندهها را قطع کنید لازم نیست نام کاربری و پسوردتان را از تک تک آنها حذف کنید.
نحوه کارکرد (به زبان ساده)
فرض کنید یک اپلیکیشن موبایل دارید به اسم Uploader دارید که میخواهد یک عکس را در یک سایت آپلود عکس به اسم Images قرار دهد. شما یک اکانت در سایت Images دارید اما نمیخواهید نام کاربری و پسوردتان را در اپلیکیشن Uploader ذخیره کنید. برحسب اتفاق اپلیکیشن Uploader به شما این امکان را میدهد که از طریق OAuth اجازه دسترسی را صادر کنید. اتفاقی که میافتد به قرار زیر است:
- اپلیکیشن Uploader به وبسایت Images یک درخواست میفرستد مبنی بر اینکه میخواهد از طرف یک کاربر به سایت دسترسی پیدا کند.
- سایت Images یک توکن یا نشانه (یک رشته یکتا از حروف، اعداد و کاراکترها) به اپلیکیشن میفرستد. این نشانه موقتی است و بعد از گذشت مدت زمان معینی منقضی میشود.
- اپلیکیشن Uploader کاربر را به وبسایت Images راهنمایی میکند. وبسایت از طریق نشانه مرحله ۲ میفهمد که اپلیکیشن Uploader کاربر را راهنمایی کرده.
- کاربر نام کاربری و پسورد خود را در وبسایت Images وارد میکند.
- وبسایت Images به کاربر اطلاع میدهد که اپلیکیشنی به نام Uploader میخواهد به جای او در وبسایت کاری انجام دهد.
- اگر کاربر تصمیم گرفت که اجازه را صادر کند، وبسایت Images همان نشانهای را که در مرحله ۲ صادر کرده بود برای اپلیکیشن میفرستد و او را مطلع میکند.
- اپلیکیشن Uploader درخواست دیگری برای وبسایت Images میفرستد و از او میخواهد نشانهای دائمی به کاربر اختصاص دهد.
- وبسایت Images نشانه را تولید میکند و به اپلیکیشن میفرستد.
- اپلیکیشن Uploader عکس را به همراه نشانهی دائمی برای وبسایت Images میفرستد.
- وبسایت Images عکس را آپلود میکند.
نحوه کارکرد (به زبان پیچیده)
عکس زیر به طور کامل و واضح مراحلی که مصرفکننده و ارائهدهنده باید طی کنند تا مصرفکننده اجازهی دسترسی داشته باشد را نشان میدهد. دقت کنید که این مراحل مربوط به وبسایت Flickr است و بعضی پارامترها را سرویس فلیکر اضافه کرده است و عمومیت ندارد
پارامترهای هر درخواست و جواب بسیار مهم هستند و اگر یکی از آنها اشتباه فرستاده یا محاسبه شود، کل عملیات متوقف میشود. در اینجا هرکدام از پارامترها را توضیح میدهم:
مرحله اول
در مرحله اول مصرفکننده یک درخواست به ارائهدهنده میفرستد و درخواست یک request token میکند.
- oauth_consumer_key: این پارامتر یک مقدار است که توسط ارائهدهنده به ازای هر مصرفکننده به صورت یکتا تولید میشود. معمولاً از طریق پنل ارائهدهنده این مقدار قابل تولید و نمایش است. پیش از فرستادن درخواست، مصرفکننده باید این مقدار را از ارائهدهنده گرفته باشد.
- oauth_nonce: این پارامتر یک مقدار منحصر به فرد به ازای هر درخواست است. مصرفکننده باید این مقدار را تولید و از یکتا بودن آن اطمینان پیدا کند. راجع به nonceها در اینجا بیشتر بخوانید.
- oauth_signature_method: یکی از مقادیر «HMAC-SHA1» یا «RSA-SHA1» یا «PLAINTEXT». به غیر از PLAINTEXT بقیه متدهای رمزنگاری درخواست هستند. به احتمال خیلی زیاد زبانی که از آن استفاده میکنید کتابخانهی مخصوص این رمزنگاریها را دارد. اگر مقدار این پارامتر برابر با PLAINTEXT باشد پارامترهای oauth_timestamp و oauth_nonce اختیاری میشوند.
- oauth_signature: درخواستی که مصرفکننده میفرستد باید امضا شود. این امضا بعداً توسط ارائهدهنده بار دیگر محاسبه میشود و فقط در صورتی که با امضای فرستاده شده برابر بود، درخواست پاسخ داده میشود. نحوهی محاسبهی امضا نیاز به توضیحات بیشتری دارد که در این پست نمیگنجد (بخش راجع به امضا را نگاه کنید)
- oauth_timestamp: تعداد ثانیههای گذشته از نیمهشب ۱ ژانویه ۱۹۷۰. این پارامتر برای این به کار میرود که ارائهدهنده بداند درخواست در چه لحظهای فرستاده شده است. با این پارامتر اگر به طور مثال پنج دقیقه از فرستاده شدن درخواست گذشته باشد میشود درخواست را رد کرد زیرا ممکن است مشکلی در سر راه به وجود آمده باشد.
- oauth_callback: آدرس معتبری که مصرفکننده روی آن انتظار جواب ارائهدهنده را میکشد. ارائهدهنده پارامترها را بررسی و جوابها را آماده میکند و به این آدرس میفرستد. این پارامتر درواقع اختیاری است اما بهتر است صراحتاً فرستاده شود تا به طور کامل بتوان ریدایرکتها را کنترل کرد. اگر مصرفکننده یک دستگاه (مانند تلفن همراه) باشد، این آدرس دیگر با پروتکل http عرضه نمیشود و باید پروتکلی که درواقع وجود ندارد را به کار برد. زیرا میخواهیم پارامترهایی که توسط این آدرس فرستاده میشود را به وسیله اپلیکیشن (و نه یک مرورگر) مدیریت کنیم. به طور مثال oauth_callback در یک اپلیکیشن اندروید میتواند myapp://authorize باشد و توسط intentها مدیریت شود. اینجا توضیحات خوبی داده شده است.
- oauth_version: این پارامتر اختیاری است. اما اگر فرستاده شود باید نسخه OAuth که استفاده میشود را فرستاد. در اینجا باید مقدارش ۱.۰ باشد.
ارائهدهنده request token را به آدرس callback مصرفکننده میفرستد.
- oauth_token: یک رشتهی یکتا. این توکن که با نام request token هم شناخته میشود، موقتی است و بعد از چند دقیقه یا چند ساعت (بسته به تنظیمات ارائهدهنده) منقضی میشود. این پارامتر برای مرحلهی بعد که کاربر باید به سایت ارائهدهنده ریدایرکت شود به درد میخورد.
- oauth_token_secret: این پارامتر در محاسبه امضا مورد استفاده قرار میگیرد. (بخش راجع به امضا را نگاه کنید)
- oauth_callback_confirmed: مقدارش فقط true است و هیچوقت false نمیشود. در واقع برای فرق گذاشتن بین نسخههای مختلف پروتکل استفاده میشود.
مرحله دوم
در مرحله دوم مصرفکننده، کاربر را به سایت ارائهدهنده ریدایرکت میکند. با این پارامترها:
- oauth_token: که همان توکن تولید شده در مرحله قبل است.
- oauth_callback: که همان شرایط مرحله قبل را دارد.
ارائهدهنده کاربر را لاگین میکند و به او پیغام میدهد که یک مصرفکننده میخواهد از طرف او فعالیتی انجام دهد. کاربر تصمیم میگیرد که این اجازه را بدهد یا نه. اگر کاربر اجازه را صادر کرد، به آدرس مصرفکننده این پارامترها فرستاده میشود:
- oauth_token: که همان توکن مرحله قبل است.
- oauth_verifier: این پارامتر یک رشتهی یکتا است که در مرحله بعد مورد استفاده قرار میگیرد.
مرحله سوم
در مرحله سوم مصرفکننده یک درخواست برای یک توکن دیگر به نام access token میفرستد. با این پارامترها:
- oauth_consumer_key: همان پارامتر در مرحله اول است.
- oauth_nonce: یک nonce یکتای دیگر برای این درخواست.
- oauth_signature_method: همان پارامتر در مرحله اول است.
- oauth_signature: همان پارامتر در مرحله اول است با این تفاوت که با توجه به پارامترهای فعلی مقدارش محاسبه میشود.
- oauth_timestamp: همان پارامتر در مرحله اول است. با این تفاوت که تعداد ثانیههای گذشته تا این لحظه (یعنی لحظهی فرستادن درخواست مرحله سوم) باید منظور شود.
- oauth_verifier: این پارامتر با مقداری که از ارائهدهنده دریافت شده است پر میشود تا معتبر بودن درخواست در مرحله سوم احراز شود. اگر این پارامتر با مقداری که ارائهدهنده پیش خود نگاه داشته است فرق داشته باشد، عملیات متوقف میشود و توکن اختصاص داده نمیشود.
- oauth_version: که همان پارامتر در مرحله اول است.
ارائهدهنده یک توکن دائمی به مصرفکننده اختصاص میدهد و آن را برای او میفرستد.
- oauth_token: یا access token یک توکن دائمی است که مصرفکننده برای دسترسی به آدرسها از آن استفاده میکند.
- oauth_token_secret: این پارامتر در محاسبهی امضا مورد استفاده قرار میگیرد. (راجع به امضا)
وقتی مصرفکننده این مقادیر را از ارائهدهنده دریافت میکند، میتواند به جای کاربر از امکانات ارائهدهنده استفاده کند. به این صورت که با هر درخواست پارامترهای زیر را میفرستد:
- oauth_token: همان secret token که از ارائهدهنده دریافت کرده است.
- oauth_consumer_key: همان پارامتر در مرحله اول است.
- oauth_signature_method: همان پارامتر در مرحله اول است.
- oauth_timestamp: همان پارامتر در مرحله اول است با این تفاوت که تعداد ثانیههای گذشته تا لحظهی فرستادن این درخواست باید لحاظ شود.
- oauth_nonce: یک nonce یکتای دیگر برای این درخواست.
- oauth_signature: همان پارامتر مرحله اول است با این تفاوت که با توجه به پارامترهای فعلی مقدار آن محاسبه میشود.
راجع به امضا
درخواستها باید امضا شوند تا فرستندهی هر درخواست مشخص شود. امضاها توسط کلیدهای مخفی (secret key) که فقط در اختیار مصرفکننده و ارائهدهنده قرار دارند رمزنگاری میشوند و به همین دلیل احتمال تقلب در ارسال درخواست توسط اسکریپتهای دیگر بسیار پایین میآید. محاسبهی امضا گرچه کار چندان سختی نیست، اما نیاز به دقت فراوان دارد. مراحل تولید امضا در اینجا به صورت دقیق بیان شده است. بر هر برنامهنویسی واجب است که آن را بخواند و به کار بگیرد.