همانطور که می دانید ، یکی از مهمترین بخشهای یک سیستم کنترل Login بودن یا نبودن کاربر و پس از آن کنترل دسترسی کاربر به یک بخش خاص از نرم افزار میباشد . در گذشته تکنولوژی WebForm هم امکاناتی فراهم نموده بود ، لاکن اکثر برنامه نویسان ترجیح میداند با ایجاد چندین جدول User ، Roles و اتصال آنها در جدولی دیگر به همدیگر ، دسترسی کاربر لاگین نموده را در هر تراکنش یا صدا زدن یک Module کنترل میکردند و در صورت عدم دسترسی کاربر ، با نمایش پیام یا .... از دسترسی کاربر به آن قسمت جلوگیری می نمودند .
بسمه تعالی
بررسی چگونگی کنترل دسترسی کاربر به صورت Dynamic در پروژه های ASP.NET MVC
همانطور که می دانید ، یکی از مهمترین بخشهای یک سیستم کنترل Login بودن یا نبودن کاربر و پس از آن کنترل دسترسی کاربر به یک بخش خاص از نرم افزار میباشد . در گذشته تکنولوژی WebForm هم امکاناتی فراهم نموده بود ، لاکن اکثر برنامه نویسان ترجیح میداند با ایجاد چندین جدول User ، Roles و اتصال آنها در جدولی دیگر به همدیگر ، دسترسی کاربر لاگین نموده را در هر تراکنش یا صدا زدن یک Module کنترل میکردند و در صورت عدم دسترسی کاربر ، با نمایش پیام یا .... از دسترسی کاربر به آن قسمت جلوگیری می نمودند .
پس از پیدایش ASP.NET MVC و Stable شدن آن در نسخه های بالای 4 و بخصوص MVC 5 ، این امکان به کاربران داده شد تا با استفاده از امکانات Identity و با استفاده از Authorize Attribute ، لاگین بودن کاربر را کنترل و در صورت عدم احراز هویت ، کاربر را به صفحه لاگین منتقل نمایند .
مسئله ای که پس از احراز هویت مطرح است ، کنترل دسترسی کاربر در ASP.NET MVC می باشد که این امر هم با استفاده از HardCode کردن User Role در Authorize Attribute و افزودن Role به جداول ایجاد شده امکان پذیر است . برای انجام این کار وضعیتی مشابه زیر بوجود خواهد آمد .
همانطور که مشاهده میکنید ، برای ایجاد دسترسی به چند Role مختلف هم می توان به شکل زیر عمل نمود .
خوب ظاهرا همه مشکلات به صورت پیش فرض توسط MVC حل شده و شما میتوانید به تعداد نامحدود Role تعریف کرده و در Controller ها با ایجاد محدودیت برای Action Method ها از آنها استفاده کنید .
حال باید دید مشکل کجاست ؟. در عمل هیچ ایرادی وجود ندارد و پروژه های کوچک و در سطح معرفی توانمندیهای MVC و ... بسیار جالب و راضی کننده به نظر می رسند ، حال اگر در یک Enterprise System قرار شد به دلایلی این سطوح دسترسی Dynamic شده و اصلن توسط خود استفاده کنندگان سیستم عملیات تعریف و Assign کردن نقش و Role انجام شود ، چه باید کرد ؟ اینجاست که برنامه نویسی که همین کار را در WebForm با نهایتا یک روز کاری انجام داده است ، به مشکل بر میخورد و گرفتار میشود . آیا میتوان روزانه Source Code پروژه را تغییر داد و مثلا چند نقش جدید ایجاد و بعد به سراغ یک به یک Controller ها که تازه معلوم نیست چه تعداد Action Method درون خود دارند رفته و Authorize Attribute را برای هریک جداگانه تغییر داد؟.
بر اساس مشاهدات بنده ، دوستان برنامه نویس زیادی با توجیهات خاص و قانع کردن مشتری به اینکه باید سیستم دارای Role ها مشخص باشد و فلسفه بافی و ... سعی نموده اند از این مشکل خلاصی یابند ، ولی حداقل خودشان میداند که توجیهاتشان قانع کننده نیست و نمی توان به آن استناد نمود .
در این مبحث خیلی کوتاه قصد دارم 80% این مشکل را برطرف نمایم . 20 درصد دیگر مربوط به این مشکل است که اکثر کاربران علاقه دارند در صورت عدم وجود دسترسی ، کاربر در همان صفحه در حال کار بماند و فقط یک پیام زیبا مبنی بر عدم دسترسی مشاهده نماید . این کار نیاز به گذاشتن زمان بیشتری دارد که در مبحث فعلی ما خارج است .
در این مقاله به شما آموزش خواهم داد که چگونه Role های Dynamic در سیستم داشته و در صورت عدم وجود دسترسی به صفحه لاگین منتقل نگردید ، بلکه به یک Custom Page با پیام عدم دسترسی منتقل شوید . مراحل زیر را دنبال کنید .
1- یک پروژه از نوع MVC به شکل زیر ایجاد کنید .
سپس نوع پروژه را مطابق زیر انتخاب کنید .
2- به سراغ WebConfing رفته و نام دیتابیس و فایل mdf را به CustomRoles تغییر دهید.
3- درون HomeController رفته و مطابق زیر برای About Action یک وضعیت نیاز به Login بودن ایجاد نمایید .
4- پروژه را Run کنید و با مراجعه به About به صفحه لاگین منتقل خواهید شد . یک کاربر بسازید و از این طریق دیتابیس برای شما ایجاد خواهد گردید .
حال خواهید دید که با هر بار مراجعه به About ابتدا Login بودن کاربر چک شده و اگر کاربر لاگین نکرده باشد ، به صفحه لاگین منتقل خواهد شد . الان وقت این است که فرض کنید جدوال Role و ... هم دارید و مشکل شما این است که باید Authorize Attribute فقط Role ها داینامیک هم بپذیرد .
برای ادامه یک کلاس به نام CustomAuthorizationAttribute به فولدر Infra اضافه کنید. بدنه کلاس در یک صفحه برای نمایش جای نخواهد گرفت ، لذا در بیش از یک تصویر درون مقاله قرار داده خواهد شد.
این کلاس باید ازAuthorizeAttribute ارث بری کند . و بدنه اولین متد به شکل زیر نوشته خواهد شد.
این متد که پس از ارث بری از AuthorizeAttribute در عمل Over Ride شده است ، وظیفه بررسی خطاهایی را دارد که در صورت عدم موفق بودن فرآیند لاگین و بررسی دسترسی و .... رخ میدهد . در صورتی که کاربر لاگین نکرده باشد ، در اولین IF به صفحه لاگین منتقل میشود و اگر لاگین بود، فعلن فرض بر این است که دسترسی لازم را نداشته است . یک Action Method به نام AccessDenied در HomeController به شکل زیر ایجاد و یک View هم به همین نام ساخته ایم . این View در صورت عدم وجود دسترسی نمایش داده خواهد شد.
View هم فقط پیغام درون ViewBag را نمایش داده و به شکل زیر است .
خوب حالا به متد بعدی درون کلاس که آن هم OverRide شده است دقت کنید.
در اینجا ابتدا Login بودن کاربر بررسی میشود . اگر کاربر لاگین کرده بود ، باید دسترسیهاش کنترل شود که این کار باید از طریق ارتباط با دیتابیس و ... انجام شود . و پس از آن مثلا بر اساس جواب دیتابیس و ... متغیر IsUserInRole مقدار دهی True یا False گردد. پس از آن باز می توان برای بازگرداندن True یا False تصمیم گرفت و بر اساس آن تصمیم گرفت . حال ببینیم در Controller چگونه میتوان از این Attribute استفاده کرد .
فقط حواستن به Infra و تعریف آن به NameSpace ها باشد .
شاید سوال کنید که برای یافتن Current Controller و Current Action Name چه باید بکنم تا بتوانم دسترسی کاربر را بر اساس آنها پیدا کنم . برای این کار هم با OverRide کردن متد OnAuthorization میتوانید این دو مقدار را مشابه زیر بدست بیاوردید.
حالا در سطح کلاس اسامی Controller و Action را داریم و میتوان به سادگی از آنها در متدهای دیگر استفاده نمود.
حالا دیگر فاصله شما تا داشتن یک سیستم دسترسی واقعی فقط کنترل این مقادیر درون دیتابیس و تصمیم گیری خواهد بود .
دانلود سورس پروژه