@elchinabilov/nestjs-ownership
v1.1.7
Published
A dynamic and recursive access control library for NestJS that enforces branch-level ownership across entities.
Readme
@elchinabilov/nestjs-ownership
A dynamic, recursive branch-based access control module for NestJS.
Installation
npm install @elchinabilov/nestjs-ownershipNə edir?
Bu modul entitilərdə filial/şöbə (branch) əsaslı sahibliyi məcburi edir. İstifadəçi yalnız özünün aid olduğu branchId-ə sahib olan resurslara daxil ola bilir. Admin rollar üçün bypass var.
Tez başlanğıc
- Modulu layihənizə qoşun (asinxron konfiqurasiya ilə):
// app.module.ts
import { Module } from "@nestjs/common";
import { TypeOrmModule, getDataSourceToken } from "@nestjs/typeorm";
import { OwnershipModule } from "@elchinabilov/nestjs-ownership";
import { DataSource } from "typeorm";
@Module({
imports: [
TypeOrmModule.forRoot({
/* ... */
}),
OwnershipModule.forRootAsync({
imports: [
TypeOrmModule.forRoot({
/* ... */
}),
],
inject: [getDataSourceToken()],
useFactory: async (dataSource: DataSource) => ({
dataSource,
// İstədiyiniz qədər entity üçün xəritə
map: {
// Açarı entity adı və ya cədvəl adı ola bilər (bax: OwnershipService.getRepositoryByName)
menu: {
// entity-dən branch-a gedən əlaqələr zənciri
// məsələn: Menu -> Restaurant -> Branch
path: ["restaurant", "branch"],
// route param-ın adı (default: "id")
idParam: "id",
},
},
// İstifadəçinin rolunun saxlandığı sahə (req.user[roleField])
roleField: "role",
// Sahibliyin müqayisə olunduğu sahə ( həm user, həm də owner obyektində )
ownershipField: "branchId",
// Admin rollar (tam bypass)
adminRoles: ["admin"],
}),
}),
],
})
export class AppModule {}- Kontroller və ya metod səviyyəsində dekoratorla entity-ni qeyd edin:
import { Controller, Get, Param, UseGuards } from "@nestjs/common";
import { Ownership, OwnershipGuard } from "@elchinabilov/nestjs-ownership";
@Controller("menus")
@Ownership("menu") // bütün metodlara şamil olunur
@UseGuards(OwnershipGuard)
export class MenuController {
@Get(":id")
// İstəsəniz metod səviyyəsində də təyin edə bilərsiniz, idParam-ı override etmək mümkündür
@Ownership("menu", { idParam: "id" })
findOne(@Param("id") id: string) {
// ...
}
}- İstifadəçinin
branchIdvəroleməlumatırequest.userdaxilində olmalıdır.
Necə işləyir?
- Guard
request.useriçindəkiroleFieldəsasında admin olub-olmadığını yoxlayır. Adminlər üçün bypass edilir. - Dekoratordan oxunan
entityKeyvəidParaməsasında resursunid-siparams/body/queryüzərindən götürülür. OwnershipService.loadOwnerThroughPathTypeORM vasitəsilə xəritədə verilmişpathüzrəLEFT JOINedərək resursun sahibini (ownerObj) çıxarır.ownerObj[ownershipField]iləuser[ownershipField]müqayisə olunur. Uyğun deyilsə403 Forbiddenatılır.idverilməyən sorğular (məs: siyahı və ya create) guard tərəfindən buraxılır.
Konfiqurasiya parametrləri
dataSource: DataSource— TypeORMDataSourceobyekti (mütləq)map: OwnershipMap— entity -> { path, idParam } xəritəsi (mütləq)roleField?: string— istifadəçi rol sahəsi; default:"role"ownershipField?: string— müqayisə sahəsi; default:"branchId"adminRoles?: string[]— admin rollar; default:["admin"]
OwnershipMap tipi:
type OwnershipMap = Record<
string,
{
path?: string[]; // entity-dən branch-a gedən əlaqələr
idParam?: string; // route param (default: "id")
}
>;Qeydlər
- Modul
@Global()olduğu üçünOwnershipGuardqlobal qeydiyyatla gəlir; lakin istəsəniz kontroller səviyyəsində də@UseGuards(OwnershipGuard)ilə tətbiq edə bilərsiniz. - Entity açarı olaraq həm entity adı, həm də cədvəl adı istifadə edilə bilər. Daxildə metadata ilə uyğunluq yoxlanılır.
src/common/ownership.map.tsfaylı geriyə uyğunluq üçün mövcuddur və tiplərisrc/common/interfaces.tsilə eyni xəttə gətirilmişdir.
Lisenzya
ISC
