در آموزش آشنایی با مفهوم RESTful API، گفتیم که یکی از خصیصههای یک ایپیآی از جنسِ رِست Stateless بودن آن است بدین معنا که هر ریکوئست ارسالی از سمت کلاینت میباید حاوی کلیهٔ اطلاعات مورد نیاز به منظور تکمیل ریکوئست (درخواست) مذکور بوده و هیچ گونه وابستگی به دیتایی همچون سِشِن که در سمت سرور ذخیره میگردد نداشته باشد. به عبارتی، اگر قصد داریم یک رِستفول ایپیآی در زبان پیاچپی توسعه دهیم، دیگر مجاز به استفاده از سِشِن نخواهیم بود. حال سؤالی که ممکن است پیش آید این است که «چگونه میتوانیم بسنجیم ببینیم که آیا کاربر لاگین کرده است یا خیر؟» که در پاسخ به این پرسش باید گفت که نیاز به آشنایی با مفهومی تحت عنوان JSON Web Token داریم اما پیش از بررسی این موضوع، نیاز است تا به بررسی این موضوع بپردازیم که اساساً سازوکار Session به چه شکل است.
برای این منظور، وبسایت سکان آکادمی را مبنا قرار میدهیم. به محض وارد کردن نامکاربری و رمزعبور در فرم ورود به سایت، چنانچه دیتای ورودی صحیح باشد لاگین خواهیم شد و از آن پس به کلیهٔ بخشهایی از سایت دسترسی خواهیم داشت که صرفاً برای کاربران ثبتنامی در نظر گرفته شدهاند. در واقع، ما به عنوان کاربر فقط و فقط یک بار نامکاربری و رمزعبور خود را وارد میکنیم اما پس از تأیید شدن هویتمان، از آن لحظه به بعد سرور میداند که ما کاربر معتبری هستیم و صفحاتی که نیاز به لاگین دارند را در معرض دیدمان قرار میدهد.
چنین امکانی از طریق مفهومی تحت عنوان Session عملی میگردد. به عبارتی، وقتی که ما نامکاربری و رمزعبور خود را وارد فرم لاگین میکنیم، در صورت درست بودن دیتای ورودی با آنچه قبلاً در دیتابیس ثبت شده است، در سمتِ سرور در فایل سیستم یک سِشِن برای شناسهٔ کاربری ما ایجاد میگردد سپس سرور آن سِشِن را برای مرورگرمان ارسال کرده و مرورگر هم آن را در قالب یک کوکی ذخیره میسازد. از این پس، با ورود به هر صفحهای که فقط برای کاربران ثبتنامی در نظر گرفته شده، کوکی مذکور حاوی یک به اصطلاح Session ID برای سرور ارسال میشود و چنانچه معتبر باشد میتوانیم آن صفحه را مشاهده کنیم و در غیر این صورت به صفحهٔ لاگین ریدایرکت خواهیم شد که چنین چیزی اصطلاحاً Session-based Authentication نامیده میشود.
در مقابل، روش دیگری نیز برای تأیید هویت کاربران داریم که تحت عنوان Token-based Authentication شناخته میشود که در توسعهٔ ایپیآی از جنس رِست کاربردی است. سازوکار این روش بدین صورت است که در سمتِ سرور یک استرینگ به صورت زیر تولید میشود:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9leGFtcGxlLm9yZyIsImF1ZCI6Imh0dHA6XC9cL2V4YW1wbGUuY29tIiwiaWF0IjoxMzU2OTk5NTI0LCJuYmYiOjEzNTcwMDAwMDAsImRhdGEiOnsiaWQiOiI5IiwiZmlyc3RuYW1lIjoiTWlrZSIsImxhc3RuYW1lIjoiRGFsaXNheSIsImVtYWlsIjoibWlrZUBjb2Rlb2ZhbmluamEuY29tIn19.h_Q4gJ3epcpwdwNCNCYxtiKdXsN34W9MEjxZ7sx21Vs
در حقیقت، بر اساس الگوریتم خاصی سرور چنین استرینگی را برای یک کاربر خاص تولید کرده و آن را در اختیار کلاینت (آیپیآی) میگذارد و از این لحظه به بعد کلاینت برای هر درخواست اچتیتیپی میباید این استرینگ را در قالب یک هِدِر در اختیار سرور بگذارد و سرور هم معتبر بودن این استرینگ را چک کرده و در صورتی که هیچ گونه مشکلی وجود نداشته باشد، درخواست کلاینت را تکمیل مینماید (همچنین اگر دیتای موجود در این توکن به هر نحوی دستخوش دستکاری گردد، امضاء توکن مذکور معتبر نبوده و سرور درخواست کاربر را عملی نخواهد کرد)
به خاطر داشته باشید |
لازم به یادآوری است که توکنها دارای یک تاریخ انقضاء هستند بدین شکل که تا وقتی موعد انقضای توکن سر نرسیده باشد، سرور آن را معتبر قلمداد خواهد کرد و در غیر این صورت، درخواست کلاینت عملی نخواهد شد و برای ادامهٔ کار نیاز به یک توکن جدید خواهد بود. |
JSON Web Token یا به اختصار JWT استانداردی که میتواند به منزلهٔ روشی برای ردوبدل کردن دیتا مابین دو سیستم در قالب جیسونی که دارای یک به اصطلاح Digital Sign (امضای دیجیتال) است مورد استفاده قرار گیرد به طوری که ساختار آن به صورت زیر است:
Header.Payload.Signature
همانطور که میبینیم، جسیون مذکور از سه بخش تشکیل شده است به طوری که با یک .
از یکدیگر مجزا شدهاند. بخش Header حاوی اطلاعاتی در ارتباط با نوع توکن + الگوریتمی است که در محاسبهٔ JWT مورد استفاده قرار خواهد گرفت که از آن جمله میتوان به SHA256 و RSA اشاره کرد به طوری که برای مثال داریم:
{
"alg": "HS256",
"typ": "JWT"
}
این دیتا در ادامه بر اساس Base64Url اِنکود میگردد تا بخش اول توکن را تشکیل دهد. بخش دوم توکن Payload نام دارد که حاوی یکسری دادهها است که داخل توکن ذخیره خواهند شد که از آن جمله میتوان به سازندهٔ توکن، تاریخ انقضاء و ... اشاره کرد. برای مثال داریم:
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
همچون مورد Header، این دادهها نیز بر اساس Base64Url اِنکود شده و بخش دوم توکن را تشکیل خواهند داد. در نهایت به Signature میرسیم که همان امضای دیجیتالی است که برای تولید این بخش نیاز به بخشهای Header و Payload به صورت اِنکودشده به علاوهٔ یک به اصطلاح Secret یا به عبارتی «کلید رمز» داریم. برای مثال، چنانچه بخواهیم از الگوریتم HMAC SHA256 استفاده نماییم، امضای دیجیتال به صورت زیر ساخته خواهد شد:
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret);
خروجی کدهای فوق یک استرینگ به اصطلاح Base64 خواهد بود که سه بخش آن با استفاده از یک .
از یکدیگر جدا شدهاند به طوری که داریم:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9leGFtcGxlLm9yZyIsImF1ZCI6Imh0dHA6XC9cL2V4YW1wbGUuY29tIiwiaWF0IjoxMzU2OTk5NTI0LCJuYmYiOjEzNTcwMDAwMDAsImRhdGEiOnsiaWQiOiI5IiwiZmlyc3RuYW1lIjoiTWlrZSIsImxhc3RuYW1lIjoiRGFsaXNheSIsImVtYWlsIjoibWlrZUBjb2Rlb2ZhbmluamEuY29tIn19.h_Q4gJ3epcpwdwNCNCYxtiKdXsN34W9MEjxZ7sx21Vs
حال زمانی که کلاینت قصد دارد ریکوئستی برای سرور ارسال کند، این توکن را در قالب هِدِری تحت عنوان Authorization
ارسال میکند. در سمت سرور نیز با دیدن توکن مذکور، دسترسی به کاربر داده خواهد شد (چنانچه این توکن حاوی حداقل دادههای مورد نیاز باشد، در این صورت دیگر کوئری زدن به دیتابیس از بین میرود.)
درآمدی بر کاربردهای JSON Web Token
به طور کلی از جمله کاربردهای جیسون وب توکن میتوان به Authorization و Information Exchange اشاره کرد که در ادامه پیرامون هر کدام توضیحاتی را ارائه خواهیم کرد.
Authorization
رایجترین کاربرد جیسون وب توکن برای تأیید هویت کاربران است که این کار اصطلاحاً Authorization نامیده میشود. زمانی که کاربر با استفاده از نامکاربری و رمزعبور خود لاگین میکند، یک توکن امضاءشده در اختیار وی قرار میگیرد تا در ریکوئستهای بعدی آن را برای سرور ارسال نموده و سرور هم پس از اطمینان حاصل کردن از صحیح بودن توکن ارسالی، دسترسیهای مورد نیاز را در اختیار کاربر خواهد گذاشت.
Information Exchange
همچنین از جیسون وب توکن به منظور تبادل دیتا به شکلی امن میتوان استفاده نمود. با توجه به اینکه JWT توسط یک جفت کلید Public/Private به صورت دیجیتالی امضاء میگردد، میتوان به این تضمین دست یافت که فقط کلاینتهایی که باید به دیتای ارسالی دسترسی خواهند یافت.
آشنایی با تفاوتهای Session-based Authentication و Token-based Authentication
برای درک بهتر تفاوتهای این دو روش از تصدیق اطلاعات کاربری، در ادامه سعی میکنیم دو سناریوی فرضی را ترسیم کنیم که به درک بهتر این مفاهیم کمک خواهد کرد.
فرض کنیم سِلف سرویس دانشگاه فقط به عرضهٔ اغذیه به دانشجویان همان دانشگاه میپردازد و از همین روی نیاز به سازوکاری خواهد داشت تا از اینکه ارباب رجوع دانشجوی همان دانشگاه باشد اطمینان حاصل کند. اولین روشی که مسئول سِلف سرویس میتواند اتخاذ کند این است که از دانشجویان بخواهد تا نام، نامخانوادگی و شمارهٔ دانشجویی خود را به محض ورود اعلام کنند. سپس وی با دپارتمان امور دانشجویان تماس حاصل نموده و اطلاعات دانشجو را در اختیار ایشان قرار میدهد و اپراتور هم دیتا را وارد یک سیستم کامپیوتری کرده و چنانچه اطلاعات با یکدیگر همخوانی داشته باشند، اعلام میکند که فرد مذکور دانشجوی همان دانشگاه است و بالتبع میتواند از سِلف سرویس استفاده کند. اگر بخواهیم مقایسهای با وب داشته باشیم، این روشی که مسئول سِلف سرویس اتخاذ کرده همان Session-based Authentication است.
در مقابل، میتوان رویکرد دیگری را نیز در سِلف سرویس دنبال کرد بدین شکل که مسئول مربوطه از دانشجویان بخواهد که کارت دانشجویی خود را نشان دهند و با فرض اینکه هر کارت یک هولوگرام داشته باشد، میتواند یک دستگاهی UV (ماوراء بنفش) داشته باشد تا معتبر بودن کارت را تست کند.
در سناریوی دوم، دپارتمان امور دانشجویان دانشگاه یک کارت در اختیار دانشجویان میگذارد که به نوعی هویت ایشان را مشخص میسازد که حاوی یک هولوگرام، امضاء یا هر نوع خصیصهٔ خاص دیگری است که وجودش به نوعی نشانگر درست بودن هویت فرد است. در چنین شرایطی، مسئول سِلف سرویس دیگر نیازی به تماس حاصل کردن با اپراتور نخواهد داشت بلکه چنانچه به نوعی به امضای روی کارت اعتماد کند، مسلماً میتواند به نام، نامخانوادگی، شمارهٔ دانشجویی و در یک کلام اینکه فرد دانشجوی همان دانشگاه باشد اعتماد کند که اگر بخواهیم مقایسهای با وب داشته باشیم، این همان روش Token-based Authentication است.