اعمال دسترسی بر روی داده ها با استفاده از Hibernate Filter

یکی از موضوعاتی که تو اغلب سامانه های نرم افزاری قطعا با اون برخواهید خورد دسترسی کاربران به داده ها است . تقریبا ۶ سال است که از یه تجربه خوب در اعمال Authotization کاربرهای درسامانه های تولیدی شرکت خودمون استفاده میکنم گفتم شاید با درمیان قرار دادن اون بتونم از نظرات شما ها استفاده کنم . ما در شرکت خودمون سامانه هایی را تولید میکنیم که در این سامانه ها کاربرانی با نقشهای متفاوتی مشغول به استفاده از سامانه هستند که هر کدوم از این سامانه ها بر اساس منطق دسترسی مشخصی داده مورد نظر خود را مشاهده میکنند . برای مثال در نظر بگیرید که سازمانی داریم که به منظور مدیریت پرسنل خود از سامانه نرم افزاری ما استفاده میکند . این سازمان دارای ساختار بسیار بزرگ میباشد . و کاربرانی در این سامانه با نقش منابع انسانی باید اطلاعات پرسنلی را به روز نگه دارند . از طرفی نقش مدیر کل منابع انسانی باید بتواند تمامی اطاعات پرسنل در این سازمان را مشاهده نماید . برای انجام این مساله به این روش عمل کردیم در ابتدا نیاز داشتیم هر کاربر سطح دسترسی خود به ساختار سازمان را مشخص نماید بنابراین به کلاس دیاگرام زیر رسیدیمبنابراین هر کاربر سامانه به یک سازمان مورد نظر دسترسی دارد .بر اساسا شکل بالا هر پرسنل در یک سازمان مشغول به کار میباشد .بنابراین لازم است هر کاربر کارمند مورد نظر خود را مشاهده نماید در این جا لازم به ذکر است که سامانه های پیاده سازی شده برای persist کردن اطلاعات در جداول از Hibernate استفاده میکند بنابراین کلاس های مورد نظر به شکل زیر تنظیم شده است .الگوی پیاده سازی برای لایه های همان لایه های استاندارد هست در نظر بگیریدی که برای خواندن داده ها کارمندان باید چه متدهای نوشته شودpublic interface EmployeeRepositoy {Employee findById(Long id,);List<Employee> findByOrganizationId(Long orgId);List<Employee> allEmployee();}همانجوری که متدهای بالا را مشاهده میکنیم قرار است لیست یا یک کارمند به عنوان خروجی برگردانده شود در صورتی که نیاز باشد برای برای این متدهای یک hql معادل نوشته شود قطعا دارای شکل زیر خواهد بود @Query(“select e from Employee e where e.organizationStructure.id in (select os.id from User u join u.organizationStructures os where u.id=?#{ principal?.id })”)Employee findById(Long id);در صورتی که دقت کرده باشید بخش زیر در تمامی query ها تکرار شده است e.organizationStructure.id in (select os.id from User u join u.organizationStructures os where u.id=?#{ principal?.id })شاید همه مثالها مثل کلاس بالا دارای سه متد نباشد . امکان دارد کلاسی باشد که دارای متدهای زیادی باشد . سوال اول این است . به چه روشی این موضوع را حل کرد روش های زیر به نظر می رسد قابل انجام باشد یک: استفاده از @Where این روش دارای مشکلات و خوبی های هست . این روش به صورت اجبار در تمامی query این فیلتر را اضافه میکند شاید نیاز باشد این فیلتر در همه حالتها اجرا نشود این روش این امکان را ندارد . مشکل دیگر عدم امکان استفاده از پارامتر در این روش هست . شاید نیاز باشد برای اعمال این منطق پارامترهایی ارسال گردد که این روش این امکان را نمیدهد . خوبی این روش این است که نیازی به فعال و غیر فعال کردن نیست و به راحتی اعمال خوهد شد دو: تعریف یه متغیر در سطح کلاس و concat کردن با query مشکل این روش این است که این امکان دارد برنامه نویس به هر دلیلی فراموش کند که این clause را به query خود concat کند . مشکل دیگر این است که این احتمال وجود دارد که در کلاس دیگری برنامه نویس روی این model یک query را اجرا نماید .در این حالت تضمینی نیست که این فیلتر اعمال شود سه: استفاده از @Filter به نظر این روش یکی از مطمین ترین روشها باشد .با استفاده از امکانی که Hibernate در اختیار ما قرار میدهد میتوان با تعریف یک فیلتر و فعال کردن ان در سطح session مطمین شد که تمامی query هایی که اجرا میشود در صورتی که دارای پیاده سازی این فیلتر در سطح مدل باشد این فیلتر در سطح آن مدل اعمال خواهد شد برای مثال