اشتراک‌ها
پروژه فارسی تل
فارسی‌تل نام پروژه‌ای است که هدف آن طراحی سیستم‌عامل کاملی برای تلفن‌های همراه هوشمند با کاربری آسان می‏باشد. این سیستم با حمایت دبیرخانهٔ شورای عالی اطلاع‌رسانی توسعه یافته و کد منبع آن به صورت متن‌باز و رایگان و در راستای پشتیبانی از خط و زبان فارسی در محیط رایانه‌ای در اختیار عموم قرار گرفته است.
پروژه فارسی تل
نظرات مطالب
معماری میکروسرویس‌ها
هر دو یکی هستند، ساخت برنامه‌های وب با محوریت سرویس‌ها، همان سرویس‌گرا میشه. در اینجا کلمه میکرو میتونه تعریف شخصی داشته باشه. توسعه دهنده‌ها میتونن تعاریف مختلفی از کوچکی یا جزء پردازی یک سرویس داشته باشن. پس تاکید بر کلمه سرویس محوری است. 
نظرات مطالب
EF Code First #11
{هم در برنامه‌های وب می‌تونه استفاده شود و هم ویندوزی}
خوب این هم باز یه نکته است. اون UoW که گفتم بالا، دقیقا مربوط میشه به این بخش. مثال:
تو کامنت قبلی از استقلال لایه سرویس عرض کردم. حالا اضافه میکنم، سرویس من داره از EF استفاده میکنه. اما مستقیما نمیاد DbContext رو صدا بزنه. بلکه اون رو از یه UoW میگیره. خاصیتش اینه که UoW من از طریق یه HttpModule وهله سازی و نابود میشه. تو نابود شدنش dirty بودنش رو بررسی و در صورت نیاز commit میشه.
حالا چطور برم رو ویندوز؟ HttpContext اگه null باشه پس رو وب نیستم! راهکارم شبیه سازی HttpContext مثلا با یه کلاس به اسم HatContext هست. حالا میتونم لایه سرویس رو هم در وب و هم در ویندوز استفاده کنم.
UoWم هم سه مرحله توسعه داره. بالاترین سطح، فقط IsDirty رو در اختیار میذاره. سطح دوم فقط Commit و Rollback و سطح سوم TContext. سطح دوم و سوم فقط در اختیار سرویس قرار داره (internal). سطح اول در اختیار کل برنامه است (public). پس IsDirty، مثلا تو WPF خیلی میتونه مفید واقع بشه. حالا Forward کردن انواع (مثلا با StructureMap) کمکم میکنه که دسترسی به هر کدوم از interface های سه گانه بالا، فقط یه نمونه رو برگردونه.

{این یه مثال انتزاعی نیست؛ دقیقا یه پروژه ی واقعی بود که درگیرش بودم.}
اشتراک‌ها
نتفلیکس و یوتوب کیفیت ویدیوهای خود را در اروپا کاهش دادند

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

نتفلیکس و یوتوب کیفیت ویدیوهای خود را در اروپا کاهش دادند
مطالب
اندکی به روز رسانی

لیست RSS وبلاگ‌های IT‌ ایرانی و همچنین فایل خلاصه وبلاگ را به روز کردم که از طریق منوی سمت راست صفحه قسمت گزیده‌ها، قابل دریافت هستند.
لیست RSS حدودا 10 کیلوبایت کاهش حجم داشته ...
لینک مربوط به فایل CHM هم پهنای باند بالایی ندارد. اگر امکان دریافت آن‌را نداشتید از لینک کمکی زیر استفاده نمائید:
دریافت


مطالب
JQuery 1.3 ارائه شد

روز قبل، نگارش رسمی و نهایی jQuery 1.3 ارائه شد و بلافاصله هم فایل مخصوص آن جهت بکارگیری intellisense ویژوال استودیو، توسط علاقمندان تهیه و عرضه گردید.

تازه‌های این نگارش:
  • Sizzle : یک موتور CSS selector قدرتمند (400 درصد بهبود سرعت نسبت به عملکرد کتابخانه قبلی در این مورد)
  • بازنگری در نحوه مدیریت رخدادها
  • موتور تزریق HTML‌ بسیار سریع (تا 15 برابر سریعتر نسبت به کتابخانه قبلی)
  • موتور بسیار سریع موقعیت یابی
  • تشخیص نوع مرورگر در آن متوقف شده و بجای آن از تشخیص ویژگی‌ها برای ماندگاری بیشتر این کتابخانه در سال‌های آتی استفاده گردیده است. (بجای بررسی userAgent ، از باگ‌های شناخته شده یا ویژگی‌های خاص، جهت تشخیص مرورگر استفاده می‌شود تا بازه وسیعی از محصولات مشابه را بتوانند پوشش دهند)
لیست کامل این تغییرات را در این آدرس می‌توانید ملاحظه نمائید.
  • جهت مشاهده و آزمایش بهبود کارآیی این کتابخانه لطفا به این صفحه مراجعه کنید. (لیست کامل این آزمایشات در انتهای صفحه لیست تغییرات، قابل دسترسی است)
همچنین تیم مربوطه در پی آن است تا در طی یکی دو هفته آینده، نگارش jQuery 1.3.1 را نیز بر اساس بازخوردهای جدید جامعه برنامه نویس‌ها ارائه دهد.

مانند همیشه این کتابخانه در دو نگارش فشرده شده (جهت استفاده در سایت‌ها) و نگارش عادی و حجیم‌تر (جهت برنامه نویسی و دیباگ کردن کدها) ارائه شده است. چون کدها در Google code هاست شده احتمالا دسترسی به آن مشکل خواهد بود. این مجموعه را از این آدرس می‌توانید دریافت کنید.

توصیه می‌شود از سرورهای سریع گوگل بعنوان هاست کتابخانه جی‌کوئری سایت‌های خود استفاده کنید. برای این منظور از آدرس زیر می‌توان استفاده کرد:
http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js


مطالب
خواندنی‌های 2 مرداد

اس کیوال سرور

الگوهای طراحی برنامه نویسی شیءگرا

امنیت

توسعه وب

دات نت فریم ورک

دبلیو اف

سی و مشتقات

کتاب‌های رایگان

لینوکس

متفرقه

محیط‌های مجتمع توسعه

مسایل انسانی، اجتماعی و مدیریتی برنامه نویسی

ویندوز

نظرات مطالب
MVVM و فراخوانی متدهای اشیاء View از طریق ViewModel
سلام.
ما در تولید محتوای فنی (در زمینه کاری خودمون و به زبان فارسی) به شکلی صحیح، مولفین انگشت شماری داریم. به نظر من برخی از مهمترین دلائل این مساله عبارت است از:

1. برخی از افراد انگل هستن - تمام! (به کتاب Harley Hahn در این زمینه مراجعه کنید).

2. بعضی ها فکر میکنن که اگر فلان مطلب رو به اشتراک بذارم، ممکنه همکارم، دوستم و ... با خوندن اون مطلب، فاصله دانسته هاشو با من کم کنه، و به این ترتیب منو با زحمت مواجه کنه (متاسفانه این خصیصه در بسیاری از شرکت های خصوصی، و تقریبا تمامی سازمان های دولتی دیده میشه).

3. وقتی گوگل و بسیاری از شرکت های شناخته شده در صنعت آگهی های Online بر اساس ضوابط کاری کشورشون، اجازه سرویس دهی به سایت هایی با مطالب فارسی رو ندارن، من نوعی از چه طریقی می تونم از نوشتن، انتفاع حاصل کنم؟ چه کنم که به شرکتهای ایرانی فعال در زمینه Ads نیز اعتمادی ندارم؟ جدا از اینکه تبلیغات این شرکت ها، اکثرا Animation هستش و من دوست دارم خواننده مطالب من، هنگام مطالعه یه مطلب فنی، احساس آرامش کنه، نه اینکه چشم هاش مدام به خاطر وجود یه آگهی َ«ـِ»ً]ٌٍ,\[]!,@# پر پر بزنه.

4. نبود قانون Copyright از دیگر دلائل عمده ای هستش که باعث شده در این زمینه ما پیشرفتی نکنیم. وقتی یکی از مطالب فارسی ای که نوشته بودم (در سال 1996 (یا 1994)، دقیق خاطرم نیست)، کپی و در یکی از جرائد کشور به اسم فرد دیگه ای منتشر شد، در همون ابتدای راه تصمیم گرفتم دیگه فارسی ننویسم. متاسفانه هنوز که هنوزه، کم و بیش شاهد این اتفاقات هستیم.

5. ...

اما در مورد مطلبی که در مورد بلاگ من فرمودید. حقیقتش بعد از اینکه فردی چند سال پیش، منو به دلیل مطالبی که به اشتراک میذاشتم به سخره گرفت و ازم پرسید که "تو اصلا میدونی معمار کیه؟"، به خودم اومدم و تصمیم گرفتم مثل وبلاگ های دیگه، به مطالب بزن و برو اکتفا نکنم. به همین دلیل، از 2/1/2010 به بعد، مطالب ارسالیم شکل مقاله به خودشون گرفتن که طبیعتا، نوشتنشون در مقایسه با نوشتن یکی دو وجب مطلب فنی، بسیار دشوارتر و زمان بر تر هست. من از March 2008 تا February 20110 در واقع برای Search Engine گوگل می نوشتم، نه برای خوانندگان. اما از اون تاریخ به بعد، مطالبی که در وبلاگم گذاشتم، توجه بسیاری از افراد رو بخودش جلب کرد و ... (بی ارتباط با موضوع گفتگو هستش، بنابراین بیش از این در این مورد توضیح نمیدم).

در هر حال، بنظر من، عدم ارائه مطالب فنی یه وبلاگ بصورت رایگان (در فرهنگ ما)، موفقیتی در پی نداره (امیدوارم برای آقای نصیری اینطور نباشه، البته اگر این وبلاگ رو از حالت رایگان در آوردن). من هنوز یادم نرفته افرادیکه برای شرکت در کنفرانس کذایی ای که بهروز راد، من و یکی دو نفر دیگه قرار بود در مورد HTML5، JavaScript Performance و ... مطلب ارائه بدیم، ابراز خرسندی کردن، اما وقت پول دادن که شد، تعداد افراد ثبت نام کننده به حداقل تعداد مورد نیاز نرسید و اون جلسه Cancel شد. جای تاسفه اگر بدونید برای یه جلسه 1 ساعته، هر نفر فقط باید 5-6 هزارتومان پرداخت می کرد...
مطالب
پیاده سازی سیاست‌های دسترسی پویای سمت سرور و کلاینت در برنامه‌های Blazor WASM
فرض کنید در حال توسعه‌ی یک برنامه‌ی Blazor WASM هاست شده هستید و می‌خواهید که نیازی نباشد تا به ازای هر صفحه‌ای که به برنامه اضافه می‌کنید، یکبار منوی آن‌را به روز رسانی کنید و نمایش منو به صورت خودکار توسط برنامه صورت گیرد. همچنین در این حالت نیاز است در قسمت مدیریتی برنامه، بتوان به صورت پویا، به ازای هر کاربری، مشخص کرد که به کدامیک از صفحات برنامه دسترسی دارد و یا خیر و به علاوه اگر به صفحاتی دسترسی ندارد، مشخصات این صفحه، در منوی پویا برنامه ظاهر نشود و همچنین با تایپ آدرس آن در نوار آدرس مرورگر نیز قابل دسترسی نباشد. امن سازی پویای سمت کلاینت، یک قسمت از پروژه‌است؛ قسمت دیگر چنین پروژه‌ای، لیست کردن اکشن متدهای API سمت سرور پروژه و انتساب دسترسی‌های پویایی به این اکشن متدها، به کاربران مختلف برنامه‌است.


دریافت کدهای کامل این پروژه

کدهای کامل پروژه‌ای که نیازمندی‌های فوق را پیاده سازی می‌کند، در اینجا می‌توانید مشاهده و دریافت کنید. در این مطلب از قرار دادن مستقیم این کدها صرفنظر شده و سعی خواهد شد بجای آن، نقشه‌ی ذهنی درک کدهای آن توضیح داده شود.


پیشنیازها

در پروژه‌ی فوق برای شروع به کار، از اطلاعات مطرح شده‌ی در سلسله مطالب زیر استفاده شده‌است:

- «اعتبارسنجی مبتنی بر JWT در ASP.NET Core 2.0 بدون استفاده از سیستم Identity»
- پیاده سازی اعتبارسنجی کاربران در برنامه‌های Blazor WASM؛ قسمت‌های 31 تا 33 .
- «غنی سازی کامپایلر C# 9.0 با افزونه‌ها»
- «مدیریت مرکزی شماره نگارش‌های بسته‌های NuGet در پروژه‌های NET Core.»
- «کاهش تعداد بار تعریف using‌ها در C# 10.0 و NET 6.0.»
- «روش یافتن لیست تمام کنترلرها و اکشن متدهای یک برنامه‌ی ASP.NET Core»


  نیاز به علامتگذاری صفحات امن شده‌ی سمت کلاینت، جهت نمایش خودکار آن‌ها 

صفحات امن سازی شده‌ی سمت کلاینت، با ویژگی Authorize مشخص می‌شوند. بنابراین قید آن الزامی است، تا صرفا جهت کاربران اعتبارسنجی شده، قابل دسترسی شوند. در اینجا می‌توان یک نمونه‌ی سفارشی سازی شده‌ی ویژگی Authorize را به نام ProtectedPageAttribute نیز مورد استفاده قرار داد. این ویژگی از AuthorizeAttribute ارث‌بری کرده و دقیقا مانند آن عمل می‌کند؛ اما این اضافات را نیز به همراه دارد:
- به همراه یک Policy از پیش تعیین شده به نام CustomPolicies.DynamicClientPermission است تا توسط قسمت‌های بررسی سطوح دسترسی پویا و همچنین منوساز برنامه، یافت شده و مورد استفاده قرار گیرد.
- به همراه خواص اضافه‌تری مانند GroupName و Title نیز هست. GroupName نام سرتیتر منوی dropdown نمایش داده شده‌ی در منوی اصلی برنامه‌است و Title همان عنوان صفحه که در این منو نمایش داده می‌شود. اگر صفحه‌ی محافظت شده‌ای به همراه GroupName نباشد، یعنی باید به صورت یک آیتم اصلی نمایش داده شود. همچنین در اینجا یک سری Order هم درنظر گرفته شده‌اند تا بتوان ترتیب نمایش صفحات را نیز به دلخواه تغییر داد.


نمونه‌ای از استفاده‌ی از ویژگی فوق را در مسیر src\Client\Pages\Feature1 می‌توانید مشاهده کنید که خلاصه‌ی آن به صورت زیر است:
 @attribute [ProtectedPage(GroupName = "Feature 1", Title = "Page 1", GlyphIcon = "bi bi-dot", GroupOrder = 1, ItemOrder = 1)]

ویژگی ProtectedPage را معادل یک ویژگی Authorize سفارشی، به همراه چند خاصیت بیشتر، جهت منوساز پویای برنامه درنظر بگیرید.


نیاز به لیست کردن صفحات علامتگذاری شده‌ی با ویژگی ProtectedPage

پس از اینکه صفحات مختلف برنامه را توسط ویژگی ProtectedPage علامتگذاری کردیم، اکنون نوبت به لیست کردن پویای آن‌ها است. اینکار توسط سرویس ProtectedPagesProvider صورت می‌گیرد. این سرویس با استفاده از Reflection، ابتدا تمام IComponentها یا همان کامپوننت‌های تعریف شده‌ی در برنامه را از اسمبلی جاری استخراج می‌کند. بنابراین اگر نیاز دارید که این جستجو در چندین اسمبلی صورت گیرد، فقط کافی است ابتدای این کدها را تغییر دهید. پس از یافت شدن IComponent ها، فقط آن‌هایی که دارای RouteAttribute هستند، پردازش می‌شوند؛ یعنی کامپوننت‌هایی که به همراه مسیریابی هستند. پس از آن بررسی می‌شود که آیا این کامپوننت دارای ProtectedPageAttribute هست یا خیر؟ اگر بله، این کامپوننت در لیست نهایی درج خواهد شد.


نیاز به یک منوساز پویا جهت نمایش خودکار صفحات امن سازی شده‌ی با ویژگی ProtectedPage

اکنون که لیست صفحات امن سازی شده‌ی توسط ویژگی ProtectedPage را در اختیار داریم، می‌توانیم آن‌ها را توسط کامپوننت سفارشی NavBarDynamicMenus به صورت خودکار نمایش دهیم. این کامپوننت لیست صفحات را توسط کامپوننت NavBarDropdownMenu نمایش می‌دهد.


تهیه‌ی جداول و سرویس‌های ثبت دسترسی‌های پویای سمت کلاینت


جداول و فیلدهای مورد استفاده‌ی در این پروژه را در تصویر فوق ملاحظه می‌کنید که در پوشه‌ی src\Server\Entities نیز قابل دسترسی هستند. در این برنامه نیاز به ذخیره سازی اطلاعات نقش‌های کاربران مانند نقش Admin، ذخیره سازی سطوح دسترسی پویای سمت کلاینت و همچنین سمت سرور است. بنابراین بجای اینکه به ازای هر کدام، یک جدول جداگانه را تعریف کنیم، می‌توان از همان طراحی ASP.NET Core Identity مایکروسافت با استفاده از جدول UserClaimها ایده گرفت. یعنی هر کدام از این موارد، یک Claim خواهند شد:


در اینجا نقش‌ها با Claim استانداردی به نام http://schemas.microsoft.com/ws/2008/06/identity/claims/role که توسط خود مایکروسافت نامگذاری شده و سیستم‌های اعتبارسنجی آن بر همین اساس کار می‌کنند، قابل مشاهده‌است. همچنین دو Claim سفارشی دیگر ::DynamicClientPermission:: برای ذخیره سازی اطلاعات صفحات محافظت شده‌ی سمت کلاینت و ::DynamicServerPermission::  جهت ذخیره سازی اطلاعات اکشن متدهای محافظت شده‌ی سمت سرور نیز تعریف شده‌اند. رابطه‌ای این اطلاعات با جدول کاربران، many-to-many است.


به این ترتیب است که مشخص می‌شود کدام کاربر، به چه claimهایی دسترسی دارد.

برای کار با این جداول، سه سرویس UsersService، UserClaimsService و UserTokensService پیش بینی شده‌اند. UserTokens اطلاعات توکن‌های صادر شده‌ی توسط برنامه را ذخیره می‌کند و توسط آن می‌توان logout سمت سرور را پیاده سازی کرد؛ از این جهت که JWTها متکی به خود هستند و تا زمانیکه منقضی نشوند، در سمت سرور پردازش خواهند شد، نیاز است بتوان به نحوی اگر کاربری غیرفعال شد، از آن ثانیه به بعد، توکن‌های او در سمت سرور پردازش نشوند که به این نکات در مطلب «اعتبارسنجی مبتنی بر JWT در ASP.NET Core 2.0 بدون استفاده از سیستم Identity» پیشتر پرداخته شده‌است.
اطلاعات این سرویس‌ها توسط اکشن متدهای UsersAccountManagerController، در اختیار برنامه‌ی کلاینت قرار می‌گیرند.


نیاز به قسمت مدیریتی ثبت دسترسی‌های پویای سمت کلاینت و سرور

قبل از اینکه بتوان قسمت‌های مختلف کامپوننت NavBarDynamicMenus را توضیح داد، نیاز است ابتدا یک قسمت مدیریتی را جهت استفاده‌ی از لیست ProtectedPageها نیز تهیه کرد:


در این برنامه، کامپوننت src\Client\Pages\Identity\UsersManager.razor کار لیست کردن کاربران، که اطلاعات آن‌را از کنترلر UsersAccountManagerController دریافت می‌کند، انجام می‌دهد. در مقابل نام هر کاربر، دو دکمه‌ی ثبت اطلاعات پویای دسترسی‌های سمت کلاینت و سمت سرور وجود دارد. سمت کلاینت آن توسط کامپوننت UserClientSidePermissions.razor مدیریت می‌شود و سمت سرور آن توسط UserServerSidePermissions.razor.
کامپوننت UserClientSidePermissions.razor، همان لیست صفحات محافظت شده‌ی توسط ویژگی ProtectedPage را به صورت گروه بندی شده و به همراه یک سری chekmark، ارائه می‌دهد. اگر در اینجا صفحه‌ای انتخاب شد، اطلاعات آن به سمت سرور ارسال می‌شود تا توسط Claim ای به نام ::DynamicClientPermission:: به کاربر انتخابی انتساب داده شود.


شبیه به همین عملکرد در مورد دسترسی سمت سرور نیز برقرار است. UserServerSidePermissions.razor، لیست اکشن متدهای محافظت شده را از کنترلر DynamicPermissionsManagerController دریافت کرده و نمایش می‌دهد. این اطلاعات توسط سرویس ApiActionsDiscoveryService جمع آوری می‌شود. همچنین این اکشن متدهای ویژه نیز باید با ویژگی Authorize(Policy = CustomPolicies.DynamicServerPermission) مزین شده باشند که نمونه مثال آن‌ها را در مسیر src\Server\Controllers\Tests می‌توانید مشاهده کنید. اگر در سمت کلاینت و قسمت مدیریتی آن، اکشن متدی جهت کاربر خاصی انتخاب شد، اطلاعات آن ذیل Claimای به نام ::DynamicServerPermission::  به کاربر انتخابی انتساب داده می‌شود.



بازگشت اطلاعات پویای دسترسی‌های سمت کلاینت از API

تا اینجا کامپوننت‌های امن سازی شده‌ی سمت کلاینت و اکشن متدهای امن سازی شده‌ی سمت سرور را توسط صفحات مدیریتی برنامه، به کاربران مدنظر خود انتساب دادیم و توسط سرویس‌های سمت سرور، اطلاعات آن‌ها را در بانک اطلاعاتی ذخیره کردیم. اکنون نوبت به استفاده‌ی از claims تعریف شده و مرتبط با هر کاربر است. پس از یک لاگین موفقیت آمیز توسط UsersAccountManagerController، سه توکن به سمت کاربر ارسال می‌شوند:
- توکن دسترسی: اطلاعات اعتبارسنجی کاربر به همراه نام و نقش‌های او در این توکن وجود دارند.
- توکن به روز رسانی: هدف از آن، دریافت یک توکن دسترسی جدید، بدون نیاز به لاگین مجدد است. به این ترتیب کاربر مدام نیاز به لاگین مجدد نخواهد داشت و تا زمانیکه refresh token منقضی نشده‌است، برنامه می‌تواند از آن جهت دریافت یک access token جدید استفاده کند.
- توکن سطوح دسترسی پویای سمت کلاینت: در اینجا لیست ::DynamicClientPermission::ها به صورت یک توکن مجزا به سمت کاربر ارسال می‌شود. این اطلاعات به توکن دسترسی اضافه نشده‌اند تا بی‌جهت حجم آن اضافه نشود؛ از این جهت که نیازی نیست تا به ازای هر درخواست HTTP به سمت سرور، این لیست حجیم claims پویای سمت کلاینت نیز به سمت سرور ارسال شود. چون سمت سرور از claims دیگری به نام ::DynamicServerPermission:: استفاده می‌کند.


اگر دقت کنید، هم refresh-token و هم DynamicPermissions هر دو به صورت JWT ارسال شده‌اند. می‌شد هر دو را به صورت plain و ساده نیز ارسال کرد. اما مزیت refresh token ارسال شده‌ی به صورت JWT، انجام اعتبارسنجی خودکار سمت سرور اطلاعات آن است که دستکاری سمت کلاینت آن‌را مشکل می‌کند.
این سه توکن توسط سرویس BearerTokensStore، در برنامه‌ی سمت کلاینت ذخیره و بازیابی می‌شوند. توکن دسترسی یا همان access token، توسط ClientHttpInterceptorService به صورت خودکار به تمام درخواست‌های ارسالی توسط برنامه الصاق خواهد شد.


مدیریت خودکار اجرای Refresh Token در برنامه‌های Blazor WASM

دریافت refresh token از سمت سرور تنها قسمتی از مدیریت دریافت مجدد یک access token معتبر است. قسمت مهم آن شامل دو مرحله‌ی زیر است:
الف) اگر خطاهای سمت سرور 401 و یا 403 رخ دادند، ممکن است نیاز به refresh token باشد؛ چون احتمالا یا کاربر جاری به این منبع دسترسی ندارد و یا access token دریافتی که طول عمر آن کمتر از refresh token است، منقضی شده و دیگر قابل استفاده نیست.
ب) پیش از منقضی شدن access token، بهتر است با استفاده از refresh token، یک access token جدید را دریافت کرد تا حالت الف رخ ندهد.

- برای مدیریت حالت الف، یک Policy ویژه‌ی Polly طراحی شده‌است که آن‌را در کلاس ClientRefreshTokenRetryPolicy مشاهده می‌کنید. در این Policy ویژه، هرگاه خطاهای 401 و یا 403 رخ دهند، با استفاده از سرویس جدید IClientRefreshTokenService، کار به روز رسانی توکن انجام خواهد شد. این Policy در کلاس program برنامه ثبت شده‌است. مزیت کار با Policyهای Polly، عدم نیاز به try/catch نوشتن‌های تکراری، در هر جائیکه از سرویس‌های HttpClient استفاده می‌شود، می‌باشد.

- برای مدیریت حالت ب، حتما نیاز به یک تایمر سمت کلاینت است که چند ثانیه پیش از منقضی شدن access token دریافتی پس از لاگین، کار دریافت access token جدیدی را به کمک refresh token موجود، انجام دهد. پیاده سازی این تایمر را در کلاس ClientRefreshTokenTimer مشاهده می‌کنید که محل فراخوانی و راه اندازی آن یا پس از لاگین موفق در سمت کلاینت و یا با ریفرش صفحه (فشرده شدن دکمه‌ی F5) و در کلاس آغازین ClientAuthenticationStateProvider می‌باشد.



نیاز به پیاده سازی Security Trimming سمت کلاینت

از داخل DynamicPermissions دریافتی پس از لاگین، لیست claimهای دسترسی پویای سمت کلاینت کاربر لاگین شده استخراج می‌شود. بنابراین مرحله‌ی بعد، استخراج، پردازش و اعمال این سطوح دسترسی پویای دریافت شده‌ی از سرور است.
سرویس BearerTokensStore، کار ذخیره سازی توکن‌های دریافتی پس از لاگین را انجام می‌دهد و سپس با استفاده از سرویس DynamicClientPermissionsProvider، توکن سوم دریافت شده که مرتبط با لیست claims دسترسی کاربر جاری است را پردازش کرده و تبدیل به یک لیست قابل استفاده می‌کنیم تا توسط آن بتوان زمانیکه قرار است آیتم‌های منوها را به صورت پویا نمایش داد، مشخص کنیم که کاربر، به کدامیک دسترسی دارد و به کدامیک خیر. عدم نمایش قسمتی از صفحه که کاربر به آن دسترسی ندارد را security trimming گویند. برای نمونه کامپوننت ویژه‌ی SecurityTrim.razor، با استفاده از نقش‌ها و claims یک کاربر، می‌تواند تعیین کند که آیا قسمت محصور شده‌ی صفحه توسط آن قابل نمایش به کاربر است یا خیر. این کامپوننت از متدهای کمکی AuthenticationStateExtensions که کار با user claims دریافتی از طریق JWTها را ساده می‌کنند، استفاده می‌کند. یک نمونه از کاربرد کامپوننت SecurityTrim را در فایل src\Client\Shared\MainLayout.razor می‌توانید مشاهده کنید که توسط آن لینک Users Manager، فقط به کاربران دارای نقش Admin نمایش داده می‌شود.
نحوه‌ی مدیریت security trimming منوی پویای برنامه، اندکی متفاوت است. DynamicClientPermissionsProvider لیست claims متعلق به کاربر را بازگشت می‌دهد. این لیست پس از لاگین موفقیت آمیز دریافت شده‌است. سپس لیست کلی صفحاتی را که در ابتدای برنامه استخراج کردیم، در طی حلقه‌ای از سرویس ClientSecurityTrimmingService عبور می‌دهیم. یعنی مسیر صفحه و همچنین دسترسی‌های پویای کاربر، مشخص هستند. در این بین هر مسیری که در لیست claims پویای کاربر نبود، در لیست آیتم‌های منوی پویای برنامه، نمایش داده نمی‌شود.


نیاز به قطع دسترسی به مسیرهایی در سمت کلاینت که کاربر به صورت پویا به آن‌ها دسترسی ندارد

با استفاده از ClientSecurityTrimmingService، در حلقه‌ای که آیتم‌های منوی سایت را نمایش می‌دهد، موارد غیرمرتبط با کاربر جاری را حذف کردیم و نمایش ندادیم. اما این حذف، به این معنا نیست که اگر این آدرس‌ها را به صورت مستقیم در مرورگر وارد کند، به آن‌ها دسترسی نخواهد داشت. برای رفع این مشکل، نیاز به پیاده سازی یک سیاست دسترسی پویای سمت کلاینت است. روش ثبت این سیاست را در کلاس DynamicClientPermissionsPolicyExtensions مشاهده می‌کنید. کلید آن همان CustomPolicies.DynamicClientPermission که در حین تعریف ProtectedPageAttribute به عنوان مقدار Policy پیش‌فرض مقدار دهی شد. یعنی هرگاه ویژگی ProtectedPage به صفحه‌ای اعمال شد، از این سیاست دسترسی استفاده می‌کند که پردازشگر آن DynamicClientPermissionsAuthorizationHandler است. این هندلر نیز از ClientSecurityTrimmingService استفاده می‌کند. در هندلر context.User جاری مشخص است. این کاربر را به متد تعیین دسترسی مسیر جاری به سرویس ClientSecurityTrimming ارسال می‌کنیم تا مشخص شود که آیا به مسیر درخواستی دسترسی دارد یا خیر؟


نیاز به قطع دسترسی به منابعی در سمت سرور که کاربر به صورت پویا به آن‌ها دسترسی ندارد

شبیه به ClientSecurityTrimmingService سمت کلاینت را در سمت سرور نیز داریم؛ به نام ServerSecurityTrimmingService که کار آن، پردازش claimهایی از نوع ::DynamicServerPermission::  است که در صفحه‌ی مدیریتی مرتبطی در سمت کلاینت، به هر کاربر قابل انتساب است. هندلر سیاست دسترسی پویایی که از آن استفاده می‌کند نیز DynamicServerPermissionsAuthorizationHandler می‌باشد. این سیاست دسترسی پویا با کلید CustomPolicies.DynamicServerPermission در کلاس ConfigureServicesExtensions تعریف شده‌است. به همین جهت هر اکشن متدی که Policy آن با این کلید مقدار دهی شده باشد، از هندلر پویای فوق جهت تعیین دسترسی پویا عبور خواهد کرد. منطق پیاده سازی شده‌ی در اینجا، بسیار شبیه به مطلب «سفارشی سازی ASP.NET Core Identity - قسمت پنجم - سیاست‌های دسترسی پویا» است؛ اما بدون استفاده‌ی از ASP.NET Core Identity.


روش اجرای برنامه

چون این برنامه از نوع Blazor WASM هاست شده‌است، نیاز است تا برنامه‌ی Server آن‌را در ابتدا اجرا کنید. با اجرای آن، بانک اطلاعاتی SQLite برنامه به صورت خودکار توسط EF-Core ساخته شده و مقدار دهی اولیه می‌شود. لیست کاربران پیش‌فرض آن‌را در اینجا می‌توانید مشاهده کنید. ابتدا با کاربر ادمین وارد شده و سطوح دسترسی سایر کاربران را تغییر دهید. سپس بجای آن‌ها وارد سیستم شده و تغییرات منوها و سطوح دسترسی پویا را بررسی کنید.