Dinamik ruxsatlarni boshqarish

Dinamik ruxsatlarni boshqarish

Men o‘tgan yili bir loyihada administratorlarga har bir resurs bo‘yicha kirish huquqlarini to‘g‘ridan-to‘g‘ri boshqarish imkonini beruvchi funksiyani joriy etish jarayonida olgan tajribalarim bilan o‘rtoqlashmoqchiman.

Xizmatni to‘xtatmasdan ruxsatlarni yangilashdan tortib, ma’lumotlar bazasi dizaynigacha bo‘lgan jarayonni real amaliy misol asosida ko‘rib chiqib, dinamik avtorizatsiyani qanday samarali joriy etish mumkinligini bosqichma-bosqich tahlil qilamiz.


1. Domen dizayni – Dinamik avtorizatsiya uchun ma’lumotlar bazasi tuzilmasi

Dinamik avtorizatsiyani qo‘llab-quvvatlash uchun yaratilgan Menu domeni quyidagicha tuzilgan:

public class Menu {
    private String id;
    private String menuContext;                // masalan: admin:project:button
    private List<String> permittedRoleCodes;  // ushbu menyuga kirishi mumkin bo‘lgan rollar
}

menuContext orqali tizimning iyerarxik tuzilmasi aniq belgilab qo‘yilgan.
Shuningdek, permittedRoleCodes ichida saqlangan ruxsat ma’lumotlari runtime (ishlash jarayoni) vaqtida moslashuvchan avtorizatsiyani amalga oshirish uchun asos yaratadi.


2. Backend – Spring AOP yordamida dinamik avtorizatsiya tekshiruvini amalga oshirish

Maxsus annotatsiya (@PermissionCheckRequired) yaratildi va uni qayta ishlovchi Aspect tashkil etildi.

Ushbu yondashuvning asosiy g‘oyasi biznes logikasi bilan avtorizatsiya logikasini to‘liq ajratishdan iborat.
PermissionCheckRequiredAspect faqat annotatsiya qiymatini olish bilan shug‘ullanadi, haqiqiy ruxsat tekshiruvi esa tashqaridan uzatilgan permissionConsumer tomonidan bajariladi. Bu esa bog‘liqlikni kamaytiradi va tizimni qo‘llab-quvvatlashni osonlashtiradi.

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PermissionCheckRequired {
    String menuContext();
}

@Aspect
@RequiredArgsConstructor
public class PermissionCheckRequiredAspect {

    @Around("@annotation({packageName}.PermissionCheckRequired)")
    public Object checkPermission(ProceedingJoinPoint point) throws Throwable {
        // annotatsiya qiymatini olish logikasi
    }
}

@Configuration
@EnableAspectJAutoProxy(exposeProxy = true)
@RequiredArgsConstructor
public class PermissionConfig {

    private final ObjectProvider<Object> beanProvider;
    private final UserSeek userSeek;

    @Bean
    public PermissionCheckRequiredAspect permissionCheckRequiredAspect() {

        return new PermissionCheckRequiredAspect(menuContext -> {
            // ruxsatni tekshirish logikasi
        });
    }
}

Endi ruxsat nazorati talab qilinadigan API metodlariga ushbu annotatsiyani qo‘shish kifoya.
Bu esa servis logikasida murakkab ruxsat tekshiruvlarini qayta-qayta yozish zaruratini bartaraf etadi.

@PostMapping("/sync-users/command")
@PermissionCheckRequired(menuContext = "admin:user:sync")
public CommandResponse syncUsers(@RequestBody SyncUsersCommand command) {
    // biznes logika
}

3. Frontend – Komponentlar orqali menyuni ro‘yxatga olish va ruxsat nazorati

Frontendda foydalanuvchiga faqat ruxsat berilgan funksiyalarni ko‘rsatish orqali chalkashlikni kamaytirish va xavfsizlik bilan bog‘liq muammolarning oldini olish muhimdir.

Buni amalga oshirish uchun ruxsatga qarab render qilishni boshqaruvchi umumiy komponent (WithPermission) yaratildi:

export const WithPermission = ({
  children,
  menuContext
}: {
  children: ReactNode;
  menuContext: string;
}) => {
  const RenderByRoles = () => {
    // ruxsatni tekshirish logikasi
  };

  return (
    <RenderByRoles />
  );
};

Ushbu komponent butun sahifani yoki alohida UI elementlarini (masalan, tugmalarni) o‘rash uchun ishlatiladi.
U backend annotatsiyalarida ishlatilgan menuContext qiymatlari bilan aynan bir xil qiymatlarni qo‘llab, izchillikni ta’minlaydi.

<WithPermission menuContext='admin:menu'>
  <MenuPageView />
</WithPermission>

Shuningdek, statik tahlil skriptlari yordamida loyiha ichidan menyu ma’lumotlarini avtomatik ravishda ajratib olish va ro‘yxatdan o‘tkazish ham mumkin.

function extractWithPermissionProps(filePaths: string[]): MenuCdo[] {
  for (const filePath of filePaths) {
    const content = fs.readFileSync(filePath, 'utf-8');

    const regex = /<WithPermission...>/g; // menyu ma’lumotlarini ajratib olish

    let match;
    while ((match = regex.exec(content)) !== null) {
      // ajratib olingan menyuni ro‘yxatdan o‘tkazish
    }
  }
}

4. Xulosa – Moslashuvchan ruxsat boshqaruvining afzalliklari

Biz dinamik avtorizatsiya tizimining to‘liq jarayonini ko‘rib chiqdik: ma’lumotlar bazasi dizaynidan boshlab, backend AOP va frontenddagi avtomatlashtirishgacha.

Avvallari menyuga kirish nazoratidagi har qanday o‘zgarish kodni o‘zgartirish va qayta deploy qilishni talab qilardi.
Endilikda esa ruxsatlarni real vaqt rejimida yangilash mumkin, bu esa xizmatni to‘xtatmasdan tezkor javob qaytarish imkonini beradi.

Hustle Paul