یک وب سرویس برای کاربرهایی با نقش (Role) های مختلف

سلام دوستان
شما اگر بخواید به کاربرهایی با نقش های مختلف دسترسی به انجام یک کار رو بدید یک وب سرویس مینویسید یا برای هر نقش یک وب سرویس جدا ؟
احساس میکنم که جمله ای که نوشتم منظورم رو نمیرسونه پس چند تا مثال میزنم.

مثلا فرض کنید یه وب سرویس داریم که یک پست رو توی دیتابیس اضافه میکنه (addPost) که هم ادمین میتونه دسترسی داشته باشه به این وب سرویس هم مثلا یوزرهای عادی اما مسئله ای که وجود داره اینه که پیادسازی این سرویس برای هر نقش متفاوت هست که این تفاوت میتونه خیلی کم یا زیاد باشه، مثلا وقتی کاربر عادی از این وب سرویس استفاده میکنه نمیتونه status پست رو تعیین کنه اما برای ادمین این محدودیت وجود نداره.

یا مثلا فرض کنید که وب سرویسی داریم که یه پست رو برمیگردونه (getPost) اما وقتی کاربر عادی از این وب سرویس استفاده میکنه فقط میتونه بعضی از field های اون پست رو ببینه اما ادمین میتونه تمام فیلد ها رو ببین.

خلاصه این که اگر شما باشید، آیا برای هر نقش یک وب سرویس جدا مینویسید یا توی همون وب سرویس نقش یا سطح دسترسی کاربر رو چک میکنید و برای هر نقش یه سری منطق رو پیاده سازی میکنید؟

اگر عنوان این پست رو بد انتخاب کردم، بفرمائید که اصلاح کنم.

2 Likes

من سعی میکنم با دادن دسترسی های مختلف کار رو جلو ببرم.
از این تاحالا استفاده نکردم ولی واسه همین کاره:

1 Likes

ممنون دوست عزیز بابت پاسخت.
بحث سطح دسترسی رو که قطعا داریم اما من مسئله ام این نیست.

ببینید شما فرض کنید یک وب سرویس داریم که برای اینکه کاربر بتونه استفاده کنه باید یک دسترسی رو داشته باشه، مثلا اسم دسترسی create_post هست، حالا دو کاربر که یکی نقش(Role) ادمین رو داره و یکی نقش مثلا کاربر عادی اما هر دو نقش، سطح دسترسی create_post رو دارن و هر دو میتونن از این وب سرویس استفاده کنن اما این سرویس برای ادمین یه جور پیاده سازی میشه و برای کاربر عادی یه جور دیگه، مثلا ادمین میتونه status پست رو هم تعیین کنه اما کاربر عادی نمیتونه.
من تو هر تیم یا پروژه ای که بودم یه راه حلی استفاده کردیم که هر کدوم مزایا و معایب خودش رو داشته اما خواستم ببینم دوستان چه راه حلی رو پیشنهاد میدن.

خب سطح دسترسیها و دسته‌بندی بخشهای مختلف میتونه توی دیتابیس ذخیره بشه. بعد موقع ساختن front-end باتوجه به اون سطوح دسترسی، بخشهایی از front-end رو کلا generate نکنیم یا غیرفعال باشه.
توی بک-اند هم وقتی ریکوئستی میاد، بررسی بشه کسی که این ریکوئست رو فرستاده، آیا دسترسی به این کار رو داشته یا نه.
این ساده‌ترین چیزیه که به ذهنم میرسه. ولی بستگی به پیاده‌سازی بخشهای دیگه و بزرگی پروژه داره.

1 Likes

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

یک سرویس می نویسی ولی هم در کد سرور هم کد client باید با توجه به نقش کاربر query رو تغییر بدی

2 Likes

نمیشه سه تا سرویس مختلف نوشت. سه‌تا مشکل پیدا میکنه.
۱- فرض کنید ۱۰تا سرویس داریم و سه تا سطح دسترسی. اونوقت باید ۳۰تا سرویس بنویسیم.
۲- و بخش بد ماجرا تعداد سرویسها نیست، بخش بدش زمانیه که میخوایم یه چیزی رو ویرایش کنیم، حداقل باید ۳ تا اون تغییرات رو انجام بدیم. این فاجعست! (و هیچ برنامه‌ای یک‌بار نوشته و تموم نمیشه، همیشه باید یه چیزی تغییر بکنه و ویرایش بیشه و ارتقاع پیدا بکنه)
۳- اگه این سه دسته‌بندیمون بخواد بشه ۴تا چی؟ قشنگ یک ماه وقت میبره تا اون نفر چهارم رو به همه‌جا اضافه کنیم و تست کنیم.

میتونیم همون ۱۰تا سرویس (۱۰تا بخش مختلف سیستممون) رو درست کنیم و توی هرکدوم یه switch-case بنویسیم. یا حالا هر چیزی که زبان مورد استفادتون داره.
و این switchها، بخش «ساختن کوئری دیتابیس» رو توی خودشون داشته باشن فقط. اینطوری (تا جایی که میتونم توی ذهنم شبیه‌سازی بکنم مشکلتون رو) ساده‌ترین حالت ممکنه و تنها بخش پیچیدش، میشه:
۱- پیدا کردن سطح دسترسی کاربری که ریکوئست زده (یه کوئری از دیتابیس میگیریم ببینیم دسترسیش چیه)
۲- سویچ، تعیین میکنه که عملیات CRUD ما باید چه کاری رو انجام بده، حالا میتونه SELECT باشه یا UPDATE یا هرچی.

اینطوری تغییر دادن (مثلا اضافه کردن یه سطح دسترسی دیگه) خیلی راحت میشه. (حداقل راحتتر از حالت قبلی)

2 Likes

ممنون سام عزیز
من هم در بیشتر پروژه ها سعی کردم با یک وب سرویس هندل کنم اما بعضی مواقع واقعا کد پیچیده شده.

این موردی که مثال زدم پیچیده نیست اما بعضی مواقع خیلی شرط ها رو باید در نظر بگیری، به خصوص توی سرویس create.
دیزاین پترن خاصی مد نظرت هست که توی همون سرویس استفاده کنیم که تمیزتر کنه کد رو؟
من خودم احساس میکنم که Chain of Responsibility شاید به درد بخوره، در واقع هر chain رو برای یک نقش در نظر بگیریم.
یا اینکه اشتباه فکر میکنم؟

1 Likes

Role based Access Control یک روش رایج این کاره، در ریلز جم cancan ببین چطوری کار می کنه

البته cancancan. اون یکی خیلی قدیمی شده و کسی توسعه‌اش نمیده.

1 Likes

بله اینو پیاده سازی میکنیم توی پروژه اما داشتم دنبال راه حلی میگشتم که از if else یا همون switch که پویا جان گفت فرار کنم :grinning:

فرار از پایه‌ای ترین بخش از اکثر زبانهای برنامه‌نویسی؟ :joy:

2 Likes

به طور کل که نمیشه کنارش گذاشت اما میشه کمتر استفاده کرد با کمک بعضی از دیزاین پترن ها که هر چند بعضی وقت ها همون دیزاین پترن کد رو پیچیده تر میکنه :grinning:

خب اون لایبرری که قراره ازش استفاده کنید هم داره ته تهش همین‌کار رو انجام میده.
من ترجیح میدم وقتی لازم میشه abstraction داشته باشم، خودم درستش کنم. اینطوری هم کنترل خیلی بهتری دارم و لازم نیست جوری که توی یه داکیومنت نوشته شده عمل کنم.

1 Likes

نه پویا جان دنبال اون لایبرری نبودم
خواستم یه طوری از switch یا if else استفاده نکنم با کمک دیزاین پترن ها

“یک if statement مهندس”

1 Likes

اگر حتی object برای هر role درست کنی بالاخره باید یک جا بر اساس منطق برنامه if یا switch داشته باشی

3 Likes

بله دقیقا
کامل که نمیشه بدونه if این مسئله رو حل کرد
اصلا هر chain یه if داخل خودش داره غالبا

1 Likes

من اولین ایده ای که به ذهنم میرسه اینه که یه سری گروه درست کنم برای هر کوئری و اون مشتری و ادمین و فلان را عضو اون گروهی کنم که اون کوئری رو باید بگیره. تغییر دادنش اینطوری راحت تره، اگر نقش ها زیادن و برای هر قسمت کوئری‌ها کم.

1 Likes