From daa28cd001e80c5cb2960136f0a243aed09795e5 Mon Sep 17 00:00:00 2001 From: Ha Minh Chien Date: Fri, 29 Dec 2023 16:56:37 +0700 Subject: [PATCH] first working casl --- .../src/domain/entity/auth/action.ts | 1 + .../src/domain/entity/auth/utils.ts | 16 ++++++++++----- .../src/domain/entity/bio-product/auth.ts | 2 +- .../domain/use-case/auth/populate-context.ts | 9 ++++++++- .../src/domain/use-case/bio-product/search.ts | 2 +- .../src/domain/use-case/bio-product/update.ts | 20 ++++++++++++++++++- 6 files changed, 41 insertions(+), 9 deletions(-) diff --git a/apps/levansy-access-service/src/domain/entity/auth/action.ts b/apps/levansy-access-service/src/domain/entity/auth/action.ts index e1de55dc..c282779c 100644 --- a/apps/levansy-access-service/src/domain/entity/auth/action.ts +++ b/apps/levansy-access-service/src/domain/entity/auth/action.ts @@ -11,6 +11,7 @@ export const AuthAction = { BioProduct: extractSecondHalf( Object.values(BioProductAction), ) as `${BioProductAction}`[], + TestCategory: extractSecondHalf( Object.values(TestCategoryAction), ) as `${TestCategoryAction}`[], diff --git a/apps/levansy-access-service/src/domain/entity/auth/utils.ts b/apps/levansy-access-service/src/domain/entity/auth/utils.ts index f90f0305..db6e5e08 100644 --- a/apps/levansy-access-service/src/domain/entity/auth/utils.ts +++ b/apps/levansy-access-service/src/domain/entity/auth/utils.ts @@ -1,4 +1,4 @@ -import { MongoAbility } from '@casl/ability' +import { MongoAbility, subject } from '@casl/ability' import { RecordTypes } from '@casl/mongoose' import { AuthAction } from './action' @@ -11,9 +11,13 @@ export function checkPermission( action: (typeof AuthAction)[TSubject][number], object?: AuthSubjectType[TSubject], ) { - const subject = AuthSubject[subjectType] - // object type injection - return ability.can(action, subject) + const subjectName = AuthSubject[subjectType] + + if (object !== undefined) { + return ability.can(action, subject(subjectName, object)) + } + + return ability.can(action, subjectName) } export function assertPermission( @@ -24,7 +28,9 @@ export function assertPermission( ) { if (!checkPermission(ability, subjectType, action, object)) { throw new EAuthzPermissionDeny( - `subject=${AuthSubject[subjectType]} action=${action} object=${object}`, + `subject=${ + AuthSubject[subjectType] + } action=${action} object=${JSON.stringify(object)}`, ) } } diff --git a/apps/levansy-access-service/src/domain/entity/bio-product/auth.ts b/apps/levansy-access-service/src/domain/entity/bio-product/auth.ts index af209795..666059b3 100644 --- a/apps/levansy-access-service/src/domain/entity/bio-product/auth.ts +++ b/apps/levansy-access-service/src/domain/entity/bio-product/auth.ts @@ -3,7 +3,7 @@ import '@casl/mongoose' export enum BioProductAction { Manage = 'manage', Read = 'read', - Delete = 'delete', + Update = 'update', } declare module '@casl/mongoose' { diff --git a/apps/levansy-access-service/src/domain/use-case/auth/populate-context.ts b/apps/levansy-access-service/src/domain/use-case/auth/populate-context.ts index 427037ca..e2239dfa 100644 --- a/apps/levansy-access-service/src/domain/use-case/auth/populate-context.ts +++ b/apps/levansy-access-service/src/domain/use-case/auth/populate-context.ts @@ -28,9 +28,16 @@ export class AuthPopulateContextUseCase { // create from user role and direct ability const ability = createMongoAbility([ { - action: BioProductAction.Delete, + action: BioProductAction.Read, subject: AuthSubject.BioProduct, }, + { + action: BioProductAction.Update, + subject: AuthSubject.BioProduct, + conditions: { + index: 2, + }, + }, ]) return { user, ability } diff --git a/apps/levansy-access-service/src/domain/use-case/bio-product/search.ts b/apps/levansy-access-service/src/domain/use-case/bio-product/search.ts index f73f7903..f6a233fb 100644 --- a/apps/levansy-access-service/src/domain/use-case/bio-product/search.ts +++ b/apps/levansy-access-service/src/domain/use-case/bio-product/search.ts @@ -24,7 +24,7 @@ export class BioProductSearchUseCase { execute(input: SearchOptions) { const { ability } = this.authContext.getData() - assertPermission(ability, 'BioProduct', BioProductAction.Manage) + assertPermission(ability, 'BioProduct', BioProductAction.Read) return this.bioProductRepository.search(input) } diff --git a/apps/levansy-access-service/src/domain/use-case/bio-product/update.ts b/apps/levansy-access-service/src/domain/use-case/bio-product/update.ts index d6bbbd32..b9eba0e9 100644 --- a/apps/levansy-access-service/src/domain/use-case/bio-product/update.ts +++ b/apps/levansy-access-service/src/domain/use-case/bio-product/update.ts @@ -1,18 +1,36 @@ import { Inject, Injectable } from '@nestjs/common' +import { BioProductAction, assertPermission } from 'src/domain/entity' import { + AuthContextToken, BioProductRepositoryToken, + IAuthContext, IBioProductRepository, } from 'src/domain/interface' +import { BioProductFindOneUseCase } from './find-one' @Injectable() export class BioProductUpdateUseCase { constructor( @Inject(BioProductRepositoryToken) private readonly bioProductRepository: IBioProductRepository, + @Inject(AuthContextToken) private readonly authContext: IAuthContext, + private readonly bioProductFindOneUseCase: BioProductFindOneUseCase, ) {} - execute(...input: Parameters) { + async execute(...input: Parameters) { + const { ability } = this.authContext.getData() + + const target = await this.bioProductFindOneUseCase.execute({ + filter: input[0], + }) + + if (target === null) { + throw new Error('not found') + } + + assertPermission(ability, 'BioProduct', BioProductAction.Update, target) + return this.bioProductRepository.update(...input) } }