Ahmadreza Mozaffary
Ahmadreza Mozaffary
خواندن ۹ دقیقه·۶ ماه پیش

نحوه پیاده سازی JWT در NET.

درود و عرض ادب من احمدرضا مظفری هستم و توی این مقاله میخوام باهاتون راجع به این ابزار/تکنولوژی صحبت کنم ، امیدوارم که براتون مفید واقع بشه 😄 ، خب بدون وقفه اضافه ، میریم که داشته باشیم .


مقاله JWT - احمدرضا مظفری
مقاله JWT - احمدرضا مظفری


این مقاله ، شامل چند بخش هست که اونارو تک به تک با هم بررسی میکنیم ، این موارد شامل :

0 ) احراز هویت و Authentication و Authotization چی هستند و تفاوتشون چیه ؟

1 ) مفهوم JWT ( بخوانید جِی-دابلیو-تی ) مخفف چی هست و به چه کاری میاد ؟

2 ) چرا به JWT نیاز داریم ؟

3) نحوه پیاده سازی JWT در اپلیکیشن دات-نتی چگونه هست ؟


فرایند احراز هویت یا Authentication یک مرحله مهم و حیاتی در توسعه وب اپلیکیشن ها یا به طور کلی ، اپلیکیشن ها هست. در طول این فرایند ما بررسی میکنیم که آیا کاربری که قصد ورود به وبسایت یا اپلیکشن مارو داره ، همون کاربری هست که باید باشه یا نه !

به بیان ساده تر ، همونطور که ما خودمون هم به عنوان user توی خیلی از سایت ها حساب داریم و هرکدوم با توجه به مشخصات حسابمون ( User credentials ) یا همون username و password مون به پنل شخصی خودمون دسترسی داریم ( و نه سایر پنل ها یا پنل سایر کاربران ) انتظار داریم که کاربران اپلیکیشنی که ما توسعه دهنده اون هستیم هم ، این امکان را داشته باشن .

البته ، این مقوله کمی فراتر از صرفا یک امکان یا فیچر کاربر پسند هست بلکه این فرایند ، یک فرایند ضروری و امنیتی مهمه ، چرا که هر کاربر باید فقط دیتاهای مربوط به حساب خودش را ببینه و نه حساب شخص دیگری رو . یا اینکه مثلا ما برای اپلیکیشن شخصی خودمون ، دسترسی های مختلفی رو داریم ، مثلا کاربر عادی ، کاربر پیشرفته و کاربر ادمین ، که هرکدوم از اونا وابسته به role خودشون ، دسترسی به بخش هایی از اپلیکیشن ما رو دارن یا اینکه ندارن . مقوله احرازهویت ( Authentication ) و مقوله ( Authorization ) با هم متفاوتن . درواقع مرحله احراز هویت ، این موضوع رو بررسی میکنه که آیا فرضا فردی با مشخصات وارد شده در صفحه login در database ما وجود داره یا نه ، حالا درصورتی که کاربر وجود نداشت ، به صفحه signup ریدایرکت میشه یا درصورتی که وجود داشت ، عملیات login وابسته به بیزنس و لاجیک مد نظر ما ، اجرا و اعمال میشه . بعد از این مرحله ، فرضا با توجه به role کاربر ، دسترسی ها روی کابر احراز هویت شده ، اعمال میشه و عملیات Authotization انجام میشه .

درحقیقت ، طبق چیزی که بالا گفته شد ، Authorization روی کاربر Authenticate شده ، اعمال میشه :). یکی از مشهور ترین متد ها و روش های توسعه احرازهویت ، استفاده از JWTـه که مخفف JSON Web Token هست . به طور کلی ، در این روش ما یک secret key در پروژه بکندی خودمون ، نگهداری میکنیم که به کمک JWT اون کلید امن رو تبدیل به یک توکن میکنیم و به کلاینت ارسال میکنیم. حالا کلاینت برای هر ریکوئستی که ارسال میکنه ، باید اعلاوه بر payload های مدنظر و header های دیفالت ، این توکن رو هم برای ما ارسال کنه! چرا که فرض کنید ما یک فرم برای ارسال تیکت در اپلیکشن خودمون داریم که مقادیر subject , sender و message را برای بکند ارسال میکنه. مقدار value این فیلد ها ، توسط کلاینت ( فرانت-اند ) دریافت ، و به عنوان یک پیلود به یک اندپوینت مشخص با مثلا متد post ارسال میشه . حالا فرض کنیم ، شخصی غیر از کاربری که باید ، این اندپوینت را به صورت مثلا دستی کپی کرده و پیلود های غیرمرتبط ( از کاربری که وجود نداره ) ارسال میکنه یا این اندپوینت را بیشمار بار فراخوانی میکنه. اینجا چه اتفاقی میوفته ؟ کلی دیتا برای ما ارسال میشه که ما حتی نمیدونیم اونو کی فرستاده و عملا احرازهویتی روی اون انجام نمیشه ! به کمک JWT ما بعد از عملیات login یک token رو از بکند دریافت میکنیم ( که میتونه تاریخ انقضا داشته باشه ) و اون رو تویه حافظه های موجود در مرورگر برای کاربر ذخیره میکنیم ( مثلا لوکال استوریج یا کوکی یا ... ). حالا به ازای هر ریکوئستی که ارسال میکنیم ، این توکن رو از استوریج های مرورگر میگیریم و به همراه پیلود ها و هدر ها ، برای بکند ارسال میکنیم و بکند توکن ارسال شده رو دریافت میکنه و اون رو دیکریپت میکنه و با اون secret key مقایسه میکنه ، اگر که یکی نبود ، خطا میده و کل فرایند اندپوینت مربوطه رو کنسل میکنه :)


چرا JWT ؟

  • فرایند Stateless: اونها ( JWTs ) مستقل هستن و می تونن اطلاعات کاربر رو ذخیره کنن و نیاز به ذخیره سازی سمت سرور یا session management را کاهش بدن.
  • احراز هویت Cross-Origin: به دلیل فرمت فشرده اونا می تونیم به راحتی توی برنامه های تک صفحه ای (SPA) و برنامه های موبایل ازشون استفاده کنیم .
  • مقیاس پذیری ( Scalability ): JWT ها رو می تونیم به راحتی توی چندین سرور توزیع و validate کرد ، که استفاده از اونا رو برای معماری های میکروسرویس ایده آل و مناسب می کنه.

تئوری کافیه :) بیاید با هم توی چند مرحله توی یک اپلیکیشنی که با دات نت 6 نوشته شده ، این تکنولوژی رو اضافه و استفاده کنیم .

  • مرحله 1: یک اپلیکیشن Net Core 6. از نوع Web API میسازیم و در آن یک کنترلر با نام دلخواه ( اینجا TestJwt ) میسازیم .

کانونشن و قرارداد این هست که اسم کنترلر به علاوه کلمه کلیدی کنترلر باشه که من اینجا رعایت نکردم ، اما شما رعایت کنین :))

مثلا بجای TestJwt باید TestJwtController باشه :)

کنترلر اولیه  | مقاله JWT - احمدرضا مظفری
کنترلر اولیه | مقاله JWT - احمدرضا مظفری

که بعد از ران کردن اپلیکیشن ، اگر که توی پست من ( PostMan ) به اندپوینت
baseurl/api/TestJwt/HelloJwt درخواست بزنیم ( baseurl = localhost, domain, etc ) توی پست من به عنوان ریسپانس هرچیزی که به Ok پاس داده باشیم رو میبینیم که اینجا Ok ما خالی هست ولی اگر مثلا توی ok بنویسم "Hello Jwt " توی مرورگر یا پست من اون متن یا ریسپانس رو میبینیم که با استاتوس کد 200 هست .


  • مرحله 2: نصب نیازمندی ها ( پکیج های NuGet )

برای اینکار میتونیم از محیط گرافیکال نوگت یا محیط CLI مربوط به dotnet برای نصب پکیج ها استفاده کنیم ، یا اینکه فایل با پسوند csproj. رو باز کنیم و رفرنس پکیج های مورد نیاز برای JWT رو مثل تصویر زیر اضافه کنیم و اون رو سیو کنیم و پکیج ها رو restore کنیم .

رفرنس پکیج های مورد نیاز JWT در NuGet | مقاله JWT - احمدرضا مظفری
رفرنس پکیج های مورد نیاز JWT در NuGet | مقاله JWT - احمدرضا مظفری


  • مرحله 3: کانفیگ کردن دیتا های مربوط به JWT در appsetting.json

جزئیات مربوط به توکنمون رو توی این فایل ، اضافه میکنیم . هرچند که موقعی که میخوایم از اونا استفاده کنیم میتونیم به طور مستقیم این مقادیر رو توی کدمون فرضا توی یک متغییر ذخیره کنیم ، اما از اونجایی که این به طوری جزو کانفیگ های داینامیک اپلیکیشنمون به حساب میاد ( مثل ConnectionString ) و ممکنه بعدا توی حالت پروداکشن احتیاج داشته باشیم که این مقادیر رو ( احتمالا ) تغییر بدیم ، بهتره که به صورت زیر اونها رو ( و البته تمامی کانفیگ هایی که از این دست هستند رو ) ذخیره و نگهداری کنیم :


کانفیگ JWT در فایل appsetting.json | مقاله JWT - احمدرضا مظفری
کانفیگ JWT در فایل appsetting.json | مقاله JWT - احمدرضا مظفری


مقدار key همون کلید یونیک انکریپت شده اپلیکیشن ما هست ( اینجا بیشتر بخونید راجع بهش ) و مقدار Issuer هم که دامینی هست که اون درخواست ازش برامون ارسال میشه ( که بعدا قطعا آپدیت میشه ! ) .

بعد از اضافه کردن این کانفیگ ، وارد فایل Program.cs میشیم و کانفیگوریشن اصلی توکنمون رو به صورت زیر انجام میدیم :

کانفیگ JWT در فایل Program.cs | مقاله JWT - احمدرضا مظفری
کانفیگ JWT در فایل Program.cs | مقاله JWT - احمدرضا مظفری


  • مرحله 4: ایجاد و ساخت توکن ها

ما میخواهیم که این توکن ها رو به محض اینکه یوزر لاگین کرد ، ایجاد کنیم و برای کلاینتمون ارسال کنیم تا اونها رو ذخیره کنه و با هر ریکوئست برای ما مجددا ارسال کنه :)

جنریت کردن توکن های JWT | مقاله JWT - احمدرضا مظفری
جنریت کردن توکن های JWT | مقاله JWT - احمدرضا مظفری

بخشی از کد بالا مربوط به فرایند لاگین کاربر هست که مشخصات اون رو با مشخصات توی دیتابیس تطابق میدیم و طبق درست بودن یا نبودن اون مشخصات ، تصمیماتی رو میگیریم . این بخش از لاجیک میتونه توی سناریو ها و اپلیکیشن های مختلف متفاوت باشه ، اما چیزی که تقریبا برای همه مشابه هست ، فرایندی هست که دربالا برای ایجاد و ساخت توکن بعد انجام چک های login مشاهده میکنید .

همونطور که میبینید توی ریسپانس Ok ما به کلاینت token ایجاد شده رو پاس میدیم :)


  • مرحله 5: اعمال Authorization روی کنترلرها یا اکشن ها

حالا که ما JWT رو کانفیگ کردیم و کلاینتمونم در صورت لاگین کردن ، توکن خودشو دریافت کرده ، وقت این رسیده که از API هامون محافظت کنیم . توی دات نت ما این کار رو میتونیم به کمک اتریبیوت [Authorize] پیش ببریم و روی اکشن یا کنترلری که به احراز هویت نیاز داره ، اون رو اضافه کنیم .

حالا فرض کنیم روی همون کنترلر اول که به اسم TestJwt ساختیم ، این اتریبیوت رو اضافه کنیم ، اتفاقی که میوفته این هست که اگر ما اون اندپوینت رو استفاده کنیم و به اون درخواستی بدیم ( بدون توکن ) به ما ریسپانس 401 UnAuthorized رو میده :) و این دقیقا همون چیزی هست که ما دنبالش بودیم .

حالا کافیه اندپوینت لاگین رو کال کنیم و به اون ریکوئست بدیم و از توکنی که اون به ما برمیگردونه استفاده کنیم و اون رو توی Header مربوط به ریکوئستمون قراربدیم و بعد درخواستمون رو به TestJwt بفرستیم . میبینیم که کار میکنه :)



سخن پایانی :

من ، احمدرضا مظفری ، از شما کمال تشکر و قدردانی رو بابت مطالعه این مقاله دارم و از شما صمیمانه درخواست میکنم که اگر نکته ای یا انتقاد یا پیشنهادی رو داشتید ، از روش های ارتباطی زیر استفاده کنید :

از طریق آدرس لینکدین من ( کلیک کنید ) یا از بخش کامنت ها ، نظراتتون رو با من درمیون بگذارید .

احراز هویتjwtAuthorizationauthenticationirandotnet
من احمدرضا مظفری به عنوان Software developer توی شرکت همکاران سیستم مشغول هستم ، توی زمینه وب ، میخونم ، یادمیگیرم ، مینویسم .
شاید از این پست‌ها خوشتان بیاید