احراز هویت بر اساس Token – مخصوص API

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

سیستم های احراز هویت سنتی

قبل اینکه در مورد سیستم های احراز هویت بر اساس Token صحبت کنیم بهتره که نگاهی به سیستم‌های سنتی بیاندازیم.

  1. کاربر نام کاربری و کلمه عبور رو وارد میکنه و روی دکمه ورود کلیک میکنه .
  2. بعد اینکه درخواست فرستاده شد، سمت back-end با استفاده از query گرفتن از دیتابیس هویت کاربر تصدیق میشه. و اگه اطلاعات درست بود یه session با استفاده از اطلاعات گرفته شده از دیتابیس ساخته میشه، و بعدش اطلاعات session تو هدر فرستاده میشد و session id تو مرورگر ذخیره میشه.
  3. با اطلاعات session مرورگر درخواست اجازه دسترسی به مناطق ممنوعه اپلیکیشن رو میخواد.
  4. و اگه session درست و مطابق دیتابیس بود اپلیکیشن اجازه دسترسی و رندر صفحه html رو میده.
traditional authentication-system

Traditional Authentication System

همه چیز تا این نقطه داره خوب کار میکنه و اپلیکیشن یه سری قسمت‌های ممنوعه داره و کاربران با اجازه دسترسی در حال مشاهده اون قسمت‌ها هستن. حالا مشکل اونجاست که ما می‌خوایم یه کلاینت دیگه بسازیم مثل اندروید یا اپلیکیشن دسکتاپ؟ آیا شما می‌تونید با این اپلیکیشنی که برای احراز هویت استفاده می‌کنید برای کلاینت های موبایل و … اجازه دسترسی به قسمت‌های اپلیکیشن رو بدید؟ اگه با همین روش بخواید احراز هویت کنید نمیشه، چرا ؟ به خاطر دو دلیل زیر :

  1. session و cookie ها برای کلاینت‌های موبایل هیچ مفهومی نداره و شما نمی تونید session یا cookie رو با اپلکیشن موبایل به اشتراک بگذارید و استفاده کنید.
  2. تو این سیستم جوابی که از طرف سرور میاد یه صفحه html هست و شما نیاز به JSON یا XML دارید تا اپلیکشن موبایل بتونه اونو پردازش کنه. تو این حالت شما یه سیستم مستقل از کلاینت دارید.

سیستم احراز هویت بر اساس Token

تو سیستم احراز هویت بر اساس Token شما نمی‌تونید از session و cookie استفاده کنید. حالا بیاید سناریوی سیستم قبلی رو برای Token ریدیزاین کنیم، روش Token از الگوریتم زیر استفاده میکنه :

  1. کاربر نام کاربری و کلمه عبور رو وارد میکنه و روی دکمه ورود کلیک میکنه
  2. بعد اینکه درخواست فرستاده شد، در سمت back-end با استفاده از query گرفتن از دیتابیس هویت کاربر تصدیق میشه. و اگه اطلاعات درست بود یه toekn با استفاده از اطلاعات گرفته شده از دیتابیس ساخته میشه. و ما هم می‌تونیم این token رو سمت کلاینت ذخیره کنیم.
  3. هر دفعه همراه هر درخواست باید این token رو بفرستیم.
  4. اگه token فرستاده شده صحیح باشه اجازه دسترسی به اون قسمت اپلیکشین رو میدیم و در هدر جواب رو به صورت XML یا JSON میفرستیم.

ما تو این حالت دیگه نه session و نه cookie بر می گردونیم و نه صفحه html، این یعنی ما می‌تونیم از این ساختار برای هر اپلیکیشنی استفاده کنیم. شمای ساختار رو می تونید تو تصویر زیر ببنید.

token-based-authentication-system

Token Based Authentication System

توی تصویر بالا دو جا کلمه JWT هست، اما این JWT چی هست ؟

JWT با حرفهای اول Json Web Token ساخته شده و یه فرمت هست که تو هدرهای احراز هویت استفاده میشه. این Token به شما کمک میکنه که ارتباط بین دو سیستم رو به صورت امن طراحی کنید. در این مطلب ما  JWT رو “bearer token” فرض میکنیم، bearer token شما از سه قسمت تشکیل شده :

  • header : نوع توکن و رمزگذاری رو ذخیر میکنه که در مثال از رمزگذاری base-64 استفاده شده .
  • payload شامل اطلاعات هست . شما هر مدل داده‌ای از جمله اطلاعات یوزر و هر چی که می‌خواید رو می‌تونید به صورت رمزگذاری شده base-64 در اینجا ذخیره کنید.
  • امضا شامل ترکیبheader , پی لود(payload)  و کلید رمز (secret key) هست. کلید رمز باید روی سرور به صورت امن نگه داشته بشه.

ساختار شمای JWT و یه مثال از Token در عکس زیر قابل مشاهده هست.

jwt-schema-png

JWT Schema png

شما نیاز نیست bearer token رو خودتون بسازید و تو زیانهای مختلف نوشته شده و می تونید تو جدول زیر لیست چند تاشو ببینید.

NodeJS : github.com/auth0/node-jsonwebtoken
PHP : github.com/firebase/php-jwt
Java : github.com/auth0/java-jwt
Ruby : github.com/progrium/ruby-jwt
.NET : github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet
Python : github.com/progrium/pyjwt/

می‌تونید اینجا یه مثال از Nodejs و Angularjs ببینید. این متن هم ترجمه شده همون سایت هست. هم کل نمونه کدها و نمونه اجرای اون‌ها رو هم می تونید اونجا ببینید.

امیر حبیب زاده

علی رغم بسیاری کسایی که تو زمینه وب و برنامه نویسی فعال هستند IT خوندم , طراحی و تولید وب اپلیکیشن با زبان PHP بلدم و قدیما با یه نیمچه فریم‌ورکی که خودم با کمک دوستانم ساخته بودم کد میزدم بعد رفتم سراغ zend دیدم اوهههه کی میخواد اینو یاد بگیره دیگه دست آخر لاراول شد فریم‌ورک مورد علاقم.

همچنین ممکن است دوست داشته باشید ...

۱۹ واکنش

  1. علی گفت:

    سلام
    ممنون خیلی توضیحات خوبی بود
    تشکر

  2. محمد جواد گفت:

    درود
    ممنون امیر بابت معرفی این راه حل خوب
    امیدوارم همه توی کشور سعی کنن همینجوری دنبال جدیدترین ها باشن
    نه مثل بعضی ها دنبال آسون‌ترین ها . . . ; )

  3. حسام ندر گفت:

    با کل قضیه موافقم خوب بود
    ولی دقیقا میشه بگی منظورت از این که session , cookie توی موبایل هیچ مفهومی نداره یعنی چی؟
    منظورت تو خارج از محیط browser هست یعنی تو اپلیکیشن؟ یا کلا گفتی؟

  4. نوید گفت:

    سلام پکیجی برای اجرای این روش روی لاراول می شناسی معرفی کنی؟

  5. مجتبی تاجیک گفت:

    Base64 رمزنگاری نیست ، صرفا یک Encoding هست .

  6. فاطمه گفت:

    خیلی خوب توضیح داده بودین . ممنون

  7. مهدی گفت:

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

  8. ممنون از توضیحاتتون.
    به این مدل توکن، Token by value هم میگن فکر کنم. البته لزومی نداره حتما اطلاعات داشته باشه توش. می تونه از نوع دوم بعنی Token by reference باشه، که صرفا یه عبارت هش شده طولانی باشه.
    یه سوال. چرا توکن رو لزوما با request header می فرستیم؟؟ دلیل خاصی داره؟ چرا به صورت درخواست معمولی نمی فرستیم؟

  9. علی جعفرآبادی گفت:

    مقاله ی #فارسی #جالب #به_روز و #خوب! بابتش خیلی ممنون. امیدوارم به عنوان یک موضوع ادامه دار تو جزئیات بشه ریز تر شد.

  10. قاسم گفت:

    مرسی عالی بود. سپاس ها

  11. MR گفت:

    چرا آخرش منبع نداره؟

  12. vahid گفت:

    دوستان کسی میدونه چجوری میشه JWT رو با اندروید پیاده کرد واسه سایت وردپرسی؟

  13. نبی گفت:

    jwt برای رمزگذاری کل اطلاعات رد و بدل شدس؟ یعنی کلاینت هم باید دیتاهای ارسالی رو رمزگذاری کنه بفرسته؟ یا باید سمت سرور خروجی رمزگذاری بشه و به کلاینت بدیم خودش بازش کنه؟ یا فقط توکن احراز هویت خودمون رو باید سمت سرور رمزگذاری کنیم …؟

    • نبی گفت:

      پاسخ سوالم رو پیدا کردم و به اشتراک میگذارم:

      >jwt برای رمزگذاری کل اطلاعات رد و بدل شدس؟
      jwt برای رمزگذاری اطلاعات نیست و بهتره بگیم برای امضاء کردن اطلاعات است!

      >یعنی کلاینت هم باید دیتاهای ارسالی رو رمزگذاری کنه بفرسته؟
      خیر، فقط توکنی که از طریق هدر دریافت کرده رو بدون دستکاری همراه داده هاش پست میکنه.

      >یا باید سمت سرور خروجی رمزگذاری بشه و به کلاینت بدیم خودش بازش کنه؟
      خیر، اطلاعات خروجی در سمت سرور نیازی به رمزگذاری یا امضاء نیستند.

      >یا فقط توکن احراز هویت خودمون رو باید سمت سرور رمزگذاری کنیم …؟
      فقط اطلاعات احراز هویت (مثلاً در ساده ترین حالت تنها یوزر آی دی) اون هم در مرتبه اول و لاگین، امضاء میشن و توکن jwt تولید شده به خروجی ارسال میشه. که در درخواست های بعدی کاربر باید اون رو از طریق هدر برای ما ارسال کنه.

  14. نبی گفت:

    ممنون بابت مقالبه خوبتون،
    چرا jwt بدون کلید رمز برگشت پذیره! اینجوری که به هیچ دردی نمیخوره! مثلاً شما میتونید اینو راحت توی سایت jwt.io بزنید و محتوا رو ببینید:
    eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJwYXNzd29yZCI6Ik1ZLXBAc3N3MDByZCJ9.OXM0GtNKQXouZgyWVz1HdSiAQnmqaldhth9Dlqe56uk
    با این حساب کاربردش رو درک نمیکنم!

    • نبی گفت:

      پاسخ سوالم رو پیدا کردم و به اشتراک میگذارم:

      jwt برای رمزگذاری نیست و بهتره بگیم برای امضاء کردن است!
      و یکی از کاربردهای اصلی اون اینه که میتونیم مطمئن بشیم داده ها دستکاری نشدند و سالم هستند.

      وقتی که مثلاً این توکن رو:
      eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.ImFzZ2hhciI.UGovjztwe0zKRkMlDXqVT1Wqb4_YKUeHRj-4RTcKBn0
      به سایت jwt.io تحویل میدیم. درسته که داده های درون اون رو نشون میده (“asghar”)، اما نکته اینجاست که در پایین صفحه قرمز رنگ مینویسه: Invalid Signature چون کلید اشتباست.
      حالا در همین لحظه در قسمت پایین که نوشته secret، کلید صحیح رو به این شکل وارد میکنیم: kelid
      بلافاصله به شکل آبی رنگ مینویسه: Signature Verified
      و این چیزیه که اهمیت داره یعنی امضاء و نه دیتایی که درون اون برگشت پذیره.

      حالا توی کد نویسی زمانی که این توکن رو با کلید اشتباه سعی میکنیم decode کنیم، جالبه که کلاس مربوطه، خطای SignatureInvalidException بر میگردونه.

      نکته بسیار مهم ماجرا اینه که اگر ما شبیه به کاری که در سایت jwt.io رخ میده، در کدنویسی هم توکن رو فقط decode کنیم همیشه موفق به اینکار میشیم و این وسط امضاء دور زده میشه، بنابراین حتماً باید وضعیت خطای SignatureInvalidException کنترل بشه تا اگر رخ داد، تابع decode کار خودش رو درست انجام نده و اطلاعات درون توکن رو برای ما محیا نکنه چراکه تائید شده نیستند.

  15. mehdi گفت:

    واقعا یک دنیا ممنون من کل سایت های انگلیسی رو زیر و رو کردم برای این که بفهمم تاکن هارو بدلیل قوی نبودن زبان نتونستم واقعا مرسی خیلی برام ضروری بود

پاسخ دهید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *