From 1df68e878896d1621123427f3b86f390df60c4fb Mon Sep 17 00:00:00 2001 From: realrafi Date: Sat, 1 Aug 2026 00:47:22 +0330 Subject: [PATCH] feat: added role decorator and guard --- src/common/decorators/role-decorator.ts | 5 ++++ src/common/enums/messages.enum.ts | 1 + src/modules/auth/guards/role-guard.ts | 40 +++++++++++++++++++++++++ 3 files changed, 46 insertions(+) create mode 100644 src/common/decorators/role-decorator.ts create mode 100644 src/modules/auth/guards/role-guard.ts diff --git a/src/common/decorators/role-decorator.ts b/src/common/decorators/role-decorator.ts new file mode 100644 index 0000000..4577609 --- /dev/null +++ b/src/common/decorators/role-decorator.ts @@ -0,0 +1,5 @@ +import { SetMetadata } from "@nestjs/common"; +import { RoleType } from "src/modules/users/enums/user-role.enum"; + +export const ROLE_KEY = 'roles'; +export const RoleDec = (...roles: RoleType[]) => SetMetadata(ROLE_KEY, roles); \ No newline at end of file diff --git a/src/common/enums/messages.enum.ts b/src/common/enums/messages.enum.ts index bd7efa1..d159ab6 100644 --- a/src/common/enums/messages.enum.ts +++ b/src/common/enums/messages.enum.ts @@ -18,6 +18,7 @@ export enum UserRoleMessages { export enum AuthMessages { TOKEN_EXPIRED_OR_INVALID = 'توکن منسوخ شده یا نامعتبر است!', + UNAUTHORIZED_ACCESS = 'شما مجاز به دسترسی به این بخش نیستید!' } export enum OrganMessages { diff --git a/src/modules/auth/guards/role-guard.ts b/src/modules/auth/guards/role-guard.ts new file mode 100644 index 0000000..3ca0825 --- /dev/null +++ b/src/modules/auth/guards/role-guard.ts @@ -0,0 +1,40 @@ +import { + CanActivate, + ExecutionContext, + ForbiddenException, + Injectable, +} from '@nestjs/common'; +import { Reflector } from '@nestjs/core'; +import { Observable } from 'rxjs'; +import { ROLE_KEY } from 'src/common/decorators/role-decorator'; +import { RoleType } from 'src/modules/users/enums/user-role.enum'; +import { IRequest } from '../interfaces/IRequest'; +import { AuthMessages } from 'src/common/enums/messages.enum'; + +@Injectable() +export class RoleGuard implements CanActivate { + constructor(private reflector: Reflector) {} + + canActivate( + context: ExecutionContext, + ): boolean | Promise | Observable { + const requiredRoles = this.reflector.getAllAndOverride( + ROLE_KEY, + [context.getHandler(), context.getClass()], + ); + + if (!requiredRoles) return true; + + const req = context.switchToHttp().getRequest(); + const user = req.user; + + if (!user) throw new ForbiddenException(AuthMessages.UNAUTHORIZED_ACCESS); + + const hasRole = requiredRoles.every((role) => user.roles.includes(role)); + + if (!hasRole) + throw new ForbiddenException(AuthMessages.UNAUTHORIZED_ACCESS); + + return true; + } +}