هوراوبلاگسطوح دسترسی در NestJS

سطوح دسترسی در NestJS

تاریخ انتشار:
1404/09/01
زمان مطالعه:
4 دقیقه
بازدید:
5 کاربر
در این مقاله می آموزیم چگونه درخواست ها را نسبت به نقش یا role کاربر محدود کنیم! موضوعی که کاربرد بسیاری در پروژه ها و وبسایت های امروزی دارد. بطور مثال یک وبسایت دانشگاهی را در نظر بگیرید، نیاز است درخواست ها نسبت به نقش کاربر ها محدود گردند؛ میهمانان، دانشجویان، اساتید و … هر کدام دسترسی های مخصوص به خودشان را دارند و در نتیجه اجازه درخواست زدن به اندپوینت هایی که مربوط به نقش آنها نمی باشد را نخواهند داشت. این سیستم تنها به وبسایت دانشگاه محدود نمیگردد، بلکه وبسایت های فروشگاهی، آموزشی و حتی خود کدنایت نیز این سیستم را در دل خود جای داده اند و کارمندان و کاربران خود را بر اساس نقش آنها محدود نموده اند. برای شروع آموزش، ابتدا به ساختار فولدر های پروژه خواهیم پرداخت که به شکل زیر است: ساختار پوشه بندی پروژه در ساختار فوق چند مدل پوشه بندی دیده می شود: src: فولدر اصلی پروژه، تمامی فایل ها و بخش های مختلف در این پوشه قرار گرفته است. common: حاوی تمامی کانفیگ ها، فانکشن ها، گارد ها و هر نوع فایلی که قرار است در کل پروژه استفاده گردد. به طور خلاصه، هر کانفیگ یا کدی که قرار است به صورت عمومی و سراسری استفاده شود، در پوشه ی common قرار خواهد گرفت. البته در این پوشه میتوانیم پوشه های بیشتری مانند اینترفیس ها، تایپ ها، اینترسپتور ها و … نیز داشته باشیم. decorator: تمامی دکوراتور های عمومی که در سرتاسر پروژه استفاده خواهد شد را در اینجا تعریف میکنیم. enums: مواردی که نیاز به تعریف شدن در قالب enum دارند، مانند رول ها و … در این فولدر مشخص می گردند. guards: در این پوشه گارد هایی مانند رول و احراز هویت قرار گرفته و به صورت عمومی تعریف خواهند شد. پوشه اصلی ما modules خواهد بود که تمامی ماژول های توسعه داده شده در این پوشه قرار خواهند گرفت. هرکدام از ماژول ها درون فولدر مربوط به خودشان هستند، مانند blog، users ،category و … تعریف نقش ها: تا اینجای کار ساختار پروژه را بطور کامل شناختید؛ حال میخواهیم نقش های سیستم را تعریف کنیم. پس در فایل role.enum.ts کد های زیر را مینویسیم : // src/common/enums/role.enum.ts export enum Role { ADMIN = 'ADMIN', USER = 'USER', GUEST = 'CLIENT', MODERATOR = 'MODERATOR' } در enumeration فوق تمامی نقش هایی که به آن نیاز خواهیم داشت را تعریف کردیم. تعریف auth.guard.ts : در این بخش کاربر را بر اساس توکنی که در اختیار دارد احراز هویت میکنیم و پس از احراز هویت، با توجه به نقشی وی دیتای او را در آبجکت ریکوئست قرار خواهیم داد، حال هر زمان نیازی به بررسی نقش باشد، به دیتای مربوطه دسترسی خواهیم داشت: // src/common/guards/auth.guard.ts import { CanActivate, ExecutionContext, Injectable, UnauthorizedException } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; import { Request } from 'express'; @Injectable() export class AuthGuard implements CanActivate { constructor(private jwtService: JwtService) { } async canActivate(context: ExecutionContext): Promise { try { const request = context.switchToHttp().getRequest(); const token = this.extractTokenFromHeader(request); if (!token) throw new UnauthorizedException(); const payload = await this.jwtService.verifyAsync(token, { secret: process.env.JWT_SECRET, }); request['user'] = payload; } catch { throw new UnauthorizedException(); } return true; } private extractTokenFromHeader(request: Request): string | undefined { const [type, token] = request.headers.authorization?.split(' ') ?? []; return type === 'Bearer' ? token : undefined; } } در کد بالا، در متد extractTokenFromHeader توکنی که در هدر درخواست کاربر موجود است را استخراج و با کمک متد canActivate توکن را وریفای کرده و دیتای وریفای یا تایید شده را با اسم user در ریکوئست قرار میدهیم. تعریف RoleDecorator: قبل از اینکه بحث role guard ها را پیش بکشیم، بهتر است در مورد نحوه ی ایجاد دسترسی به اندپوینت ها و چگونگی ساخت یک custom decorator از طریق metadata صحبت کنیم. به کمک این دکوراتور می توانیم برای یک اندپوینت، سطوح دسترسی تعیین کنیم و بگوییم چه نقش هایی می توانند به این اندپوینت دسترسی داشته باشند: // src/common/decorators/role.decorator.ts import { SetMetadata } from '@nestjs/common'; import { Role } from 'src/common/enums/role.enum'; export const ROLE_KEY = 'role'; export const Roles = (...role: Role[]) => SetMetadata(ROLE_KEY, role); در کد فوق، ما یک key با اسم role را در متغیر ROLE_KEY قرار دادیم که با کمک این key، می توانیم به هر دیتایی که در metadata با این اسم جابجا شد دسترسی داشته باشیم. تعریف RoleGuard: در این بخش نقش هایی که از طریق دکوراتور Roles به اندپوینت داده می شود را در اختیار داریم و همچنین نقش کاربر که از طریق authGuard بدست آوردیم را نیز می دانیم، در نتیجه مشخص میکنیم که کاربر دسترسی لازم را دارد یا خیر: // src/common/guards/role.guard.ts import { CanActivate, ExecutionContext, ForbiddenException, Injectable } from "@nestjs/common"; import { Reflector } from "@nestjs/core"; import { Request } from "express"; import { ROLE_KEY } from "src/common/decorators/role.decorator"; import { Role } from "src/common/enums/role.enum"; export class TokenDto { id: number; role: Role; } @Injectable() export class RoleGuard implements CanActivate { constructor( private reflector: Reflector, ) { } async canActivate(context: ExecutionContext) { const requiredRoles = this.reflector.getAllAndOverride(ROLE_KEY, [ context.getHandler(), context.getClass() ]); const req: Request = context.switchToHttp().getRequest(); const token = req['token']; let userRole = token?.role; if (!requiredRoles || requiredRoles.length == 0) return true; const accessResult = requiredRoles.some(role => role === userRole); if (accessResult) return accessResult; throw new ForbiddenException(); } } همانطور که در کد بالا مشاهده می کنید، نقش کاربر با نقش های وارد شده برای اندپوینت مقایسه می گردد و اگر کاربر حداقل یکی از نقش های مورد نیاز را داشته و یا نقش های مشخص شده برای اندپوینت خالی و بدون مقدار باشد، میتواند به کار خود ادامه دهد. اعمال سطح دسترسی بر روی متد ها در کنترلر: برای اینکه بتوانیم محدودیت های مورد نیاز را بر روی هر کدام از مسیرها یا اندپوینت ها اعمال نماییم، باید با کمک دکوراتور Roles مشخص کنیم که چه نقش هایی میتوانند به آن اندپوینت دسترسی لازم را داشته باشند. برای درک بهتر این مفهوم کد های زیر را دنبال کنید: import { Controller, Get, UseGuards } from '@nestjs/common'; import { Role } from 'src/common/enums/role.enum'; import { Roles } from 'src/common/decorators/role.decorator'; import { AuthGuard } from 'src/common/guards/auth.guard'; import { RoleGuard } from 'src/common/guards/role.guard'; @Controller("post") export class PostController { @Get('admin-access') @Roles(Role.ADMIN) @UseGuards(AuthGuard, RoleGuard) async adminOnlyEndpoint() { return "Welcome admin"; } @Get('profile') @Roles() @UseGuards(AuthGuard, RoleGuard) async profile() { return "this is my profile"; } @Get('create') @Roles(Role.ADMIN, Role.MODERATOR) @UseGuards(AuthGuard, RoleGuard) async create() { return "Created Post"; } } در کد های بالا اند پوینت ها را بر اساس نقش های مختلف محدود کردیم، لازم به ذکر است اگر بخواهیم یک یا چند اندپوینت را محدود نکنیم، به طوری که همه بتوانند به آن دسترسی داشته باشند، فقط کافیست دکوراتور Roles را برای آن اندپوینت قرار ندهیم یا ورودی های آن را خالی بگذاریم. نتیجه گیری: در این مقاله با سیستم RBAC آشنا شدیم و همچنین آموختیم چگونه می توانیم در فریمورک نست جی اس، چنین سیستمی را پیاده سازی کنیم. این فریم ورک قدرتمند، مجموعه ای بی نظیر از ابزارهای مختلف را در اختیار ما قرار می دهد که مدیریت و کنترل موارد این چنینی را بسیار ساده و لذت بخش خواهد نمود.
برگ

مقالات مرتبط

سه روش برای عبور از تحریم های داکر!
docker

با توجه به تحریم های داکر (و متاسفانه بسیاری از وبسایت های دیگر!)، دولوپر ها و مهندسین دوآپس ایرانی نمی توانند به راحتی با داکر کار کرده و ایمیج های آن را pull کنند؛ در نتیجه زمانی که میخواهیم ایمیجی را pull کنیم یا آن را به داکر هاب ارسال کنیم، داکر خطایی تحت عنوان ۴۰۳ ارسال می کند که این خطا، به معنی عدم دسترسی یا Forbidden می باشد.

ح
حسین فلاح
Schedule یا کرون جاب ها در NodeJs
nesths

نود جی اس یک پلتفرم عالی برای توسعه بک اند می باشد و اکثر برنامه هایی که توسعه داده میشوند یک نیاز مشترک دارند آن هم اجرای وظایفی می باشد که در یک تایم مشخص باید اجرا شوند، مانند پاک کردن دیتاهای قدیمی یا ارسال تعداد زیادی ایمیل در ساعت خلوتی اپ و یا عملیات تسویه حساب مالی با کاربران سر یک ساعت مشخص و … از نمونه عملیات هایی میباشد که میتوان با jobs یا schedule انجام داد

ح
حسین فلاح
سطوح دسترسی در NestJS
nesths

کنترل دسترسی مبتنی بر RBAC یا Role Based Access Control

ح
حسین فلاح
7 ترفند مهم تایپ اسکریپتی
typescript

با کمک تایپ اسکریپت، میتوان ورودی ها، خروجی ها و همچنین شیوه ی رفتار متدها و توابع را مشخص نمود؛ همچنین استفاده از انواع تایپ ها و ابزار ها در کنار یکدیگر بسیار لذت بخش و جالب خواهد بود. پس در ادامه با کدنایت همراه باشید.

ح
حسین فلاح

نظر خود را درباره محصول وارد کنید.

نظرات (0)

آخرین: