نحوه افزودن احراز هویت مبتنی بر JWT در NestJS
احراز هویت یک جنبه بسیار مهم در توسعه نرم افزار است. این فرآیند تأیید هویت کاربر است.
احراز هویت تضمین می کند که فقط افراد مجاز به منابع خاصی دسترسی دارند یا اقدامات خاصی را در یک سیستم انجام می دهند. با فعال کردن ردیابی اقدامات کاربر و مسئول نگه داشتن افراد در قبال فعالیت هایشان، مسئولیت پذیری را فراهم می کند.
همچنین داده هایی را در مورد تعداد افرادی که از محصولات آنها استفاده می کنند به شرکت ها می دهد. بدون احراز هویت مناسب نرم افزار خود، ممکن است با خطرات امنیتی روبرو شوید. اجرای صحیح از دسترسی غیرمجاز جلوگیری می کند و از داده های حساس محافظت می کند.
این آموزش شما را در ساخت یک احراز هویت کاربر مبتنی بر JWT در NestJS و MongoDb راهنمایی می کند.
NestJS یک چارچوب قدرتمند Node.js برای ساخت سمت سرور است
برنامه های کاربردی. MongoDB پایگاه داده محبوب NoSQL است و ما از آن برای ساختن نقاط پایانی احراز هویت اولیه استفاده خواهیم کرد.
در این آموزش به موضوعات زیر می پردازیم:
نحوه ایجاد یک پروژه جدید NestJS و نصب وابستگی های لازم.
نحوه ایجاد مدل ها و طرحواره های کاربری
نحوه پیاده سازی ورود و ثبت نام با توکن JWT.
نحوه تست نقاط پایانی با پستچی
پیش نیازها
این آموزش یک دمو عملی است. برای دنبال کردن، باید آن را داشته باشید
ذیل:
Node.js نسخه 14
و بالاتر
مدیر بسته گره
درک اولیه Node.js و ترجیحا ExpressJs
یک ویرایشگر کد (به عنوان مثال: VS Code)
نحوه راه اندازی پروژه
در این بخش، پروژه ای را برای ساخت REST API خود راه اندازی می کنیم
NestJS و MongoDB. ما با نصب NestJS CLI و استفاده از آن برای تولید پروژه های جدید شروع می کنیم.
$ npm i -g @nestjs/cli
سپس با این دستور یک پروژه جدید NestJS ایجاد کنید:
$ nest new project-name
بیایید احراز هویت پروژه را صدا کنیم:
$ nest new authentication
گزینه هایی در مورد اینکه کدام مدیر بسته را ترجیح می دهید نصب کنید را مشاهده خواهید کرد. من
npm استفاده شده است.
پس از نصب موفقیت آمیز، به پوشه ایجاد شده بروید و باز کنید
پروژه با ویرایشگر کد دلخواه شما.
قبل از اینکه به ایجاد منابع و پیکربندی پروژه بپردازیم، اجازه دهید
نگاهی گذرا به دایرکتوری src و فایل های آن بیندازید:
src
: دایرکتوری ریشه برای کد منبع.
src/app.module.ts
: ماژول اصلی برنامه برای پیکربندی و
ادغام ماژول های دیگر
src/app.controller.ts
: شامل یک کنترلر پیش فرض با یک واحد است
مسیر
src/app.service.ts
: این شامل یک سرویس پایه با استفاده از یک واحد است
روش.
src/main.ts
: نقطه ورود برنامه.
در مرحله بعد، وابستگی ها را برای راه اندازی و اتصال پایگاه داده نصب کنید. شما باید بسته mongoose
، bcrypt
را نصب کنید:
$ npm i -save @nestjs/mongoose @types/bcrypt mongoose bcrypt
بعد، پایگاه داده خود را تنظیم کنید. MongooseModule
از وابستگی @nestjs/mongoose
برای راه اندازی پایگاه داده استفاده خواهد شد.
به فایل src/app.module.ts
بروید:
import { AppController } from './app.controller'; import { AppService } from './app.service'; import { MongooseModule } from '@nestjs/mongoose'; import { UsersModule } from './users/users.module'; import { AuthModule } from './auth/auth.module'; import { ConfigModule } from '@nestjs/config'; @Module({ imports: [ MongooseModule.forRoot('mongodb://localhost:27017/auth-workshop'), UsersModule, AuthModule, ConfigModule.forRoot({ envFilePath: '.env', isGlobal: true, }), ], controllers: [AppController], providers: [AppService], }) export class AppModule {}
بیایید کد بالا را تجزیه کنیم.
app.module.ts
ماژول اصلی برنامه nestjs است و وظیفه وارد کردن وابستگی ها و سایر ماژول های مورد نیاز برنامه، پیکربندی برنامه مانند اتصالات پایگاه داده و متغیرهای محیطی را بر عهده دارد.
ما ابتدا فایل app.module.ts
را به عنوان یک ماژول با استفاده از دکوراتور @Module({})
مشخص کردیم:
@Module({})
آرایه imports
ماژولی را مشخص می کند که این ماژول به آن وابسته است. ما MongooseModule.forRoot('')
برای اتصال به پایگاه داده با استفاده از mongoose داریم، ConfigModule.forRoot
import ماژول پیکربندی را برای خواندن از یک فایل .env
تنظیم می کند:
import { MongooseModule } from '@nestjs/mongoose'; import { UsersModule } from './users/users.module'; import { AuthModule } from './auth/auth.module'; import { ConfigModule } from '@nestjs/config'; imports: [ MongooseModule.forRoot('mongodb://localhost:27017/auth-workshop'), UsersModule, AuthModule, ConfigModule.forRoot({ envFilePath: '.env', isGlobal: true, }), ]
شما می توانید رشته URI MongooseModule.forRoot()
را با پایگاه داده خود جایگزین کنید
رشته
آرایه controllers
کنترل کننده ای را که به این ماژول تعلق دارد را مشخص می کند:
controllers: [AppController]
آرایه providers
خدمات متعلق به این ماژول را مشخص می کند:
providers: [AppService]
با این تنظیمات می توانید برنامه خود را با استفاده از
npm run start:dev
.
مدل ها و طرحواره های کاربر
در این بخش، مدل User
و طرحواره را با استفاده از آن تعریف می کنیم
mongoose
. مدل User
نشان دهنده کاربران برنامه خواهد بود،
و این طرح ساختار داده های ذخیره شده در MongoDB را تعریف می کند.
بیایید با ایجاد یک ماژول منبع برای API کاربران شروع کنیم:
ابتدا یک منبع users
با CLI تودرتو ایجاد کنید:
$ nest generate res users
این دستور یک منبع users
جدید در src/users ایجاد می کند
دایرکتوری با ساختار پایه ای از کنترلرها و خدمات.
سپس طرحی را برای Users
در src/users/entities/users.entity.ts تعریف کنید:
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; @Schema() export class User { @Prop() name: string; @Prop({ unique: true }) email: string; @Prop() password: string; } export const UserSchema = SchemaFactory.createForClass(User);
دکوراتور @Schema
چیزی است که کلاس را به یک طرحواره تبدیل می کند. این طرح سه فیلد را برای کاربران تعریف می کند: name
، email
و password
. همه آنها رشته ای تایپ شده اند.
سپس، طرح را در فایل users.module.ts
واقع در src/users/users.module.ts ثبت کنید:
import { Module } from '@nestjs/common'; import { UsersService } from './users.service'; import { UsersController } from './users.controller'; import { MongooseModule } from '@nestjs/mongoose'; import { UserSchema, User } from './entities/user.entity'; @Module({ imports: [MongooseModule.forFeature([{ name: User.name, schema: UserSchema }])], controllers: [UsersController], providers: [UsersService], }) export class UsersModule {}
با وارد کردن MongooseModule.forFeature([{}])
، mongoose را برای استفاده از UserSchema
برای مدل User
پیکربندی میکند.
با ثبت طرح با Mongoose، مدلی ایجاد کردیم که آماده استفاده در برنامه ما است. این زمینه را برای ساختن خدمات و کنترلکنندههایی فراهم میکند که میتوانند با دادههای ما تعامل داشته باشند و درخواستهای دریافتی را مدیریت کنند.
در نهایت، DTO (شیء انتقال داده) را تعریف کنید. این شی داده ها را بین سیستم ها منتقل می کند. این یک شی ساده است که فقط حاوی داده است و هیچ رفتاری ندارد.
CreateUserDto
خود را در دایرکتوری src/users/dto/create-user.dto.ts ایجاد کنید:
export class CreateUserDto { username: string; email: string; password: string; }
خدمات کاربر و کنترلرها
ما به پایگاه داده متصل شده ایم و طرح و مدل Users
را ایجاد کرده ایم. بیایید روش های اولیه CRUD را برای کاربران بنویسیم.
users.service.ts خود را که در src/users/users.service.ts قرار دارد به روز کنید:
import { Injectable, NotFoundException } from '@nestjs/common'; import { CreateUserDto } from './dto/create-user.dto'; import { UpdateUserDto } from './dto/update-user.dto'; import { InjectModel } from '@nestjs/mongoose'; import { User } from './entities/user.entity'; import { Model } from 'mongoose'; @Injectable() export class UsersService { constructor(@InjectModel(User.name) private userModel: Model<User>) {} async createUsers(createUserDto: CreateUserDto) { const user = await this.userModel.create(createUserDto); return user.save(); } async findAllUsers() { const users = this.userModel.find(); return users; } async findUser(id: number) { const user = await this.userModel.findById(id); if (!user) throw new NotFoundException('could not find the user'); return user; } updateUser(id: number, updateUserDto: UpdateUserDto) { return this.userModel.findByIdAndUpdate(id, updateUserDto, { new: true }); } removeUser(id: number) { return this.userModel.findByIdAndDelete(id); }; }
users.controller.ts خود را که در src/users/users.controller.ts قرار دارد به روز کنید:
import { Controller, Get, Post, Body, Patch, Param, Delete, } from '@nestjs/common'; import { UsersService } from './users.service'; import { CreateUserDto } from './dto/create-user.dto'; import { UpdateUserDto } from './dto/update-user.dto'; @Controller('users') export class UsersController { constructor(private readonly usersService: UsersService) {} @Post() async create(@Body() createUserDto: CreateUserDto) { return await this.usersService.createUsers(createUserDto); } @Get() async findAll() { return await this.usersService.findAllUsers(); } @Get(':id') async findOne(@Param('id') id: string) { return await this.usersService.findOneUser(+id); } @Patch(':id') async update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) { return await this.usersService.updateUser(+id, updateUserDto); } @Delete(':id') async remove(@Param('id') id: string) { return await this.usersService.removeUser(+id); } }
ما API های RESTful را با استفاده از mongoose
ایجاد کردیم. روش ها عبارتند از:
findAllUsers
: تمام اسناد کاربر را از مجموعه بازیابی می کند.
getUserById
: یک سند کاربر را بر اساس شناسه پیدا می کند.
createUsers
: یک سند کاربر جدید را به مجموعه اضافه می کند.
updateUser
: جزئیات کاربر موجود در مجموعه را به روز می کند.
removeUser
: سند کاربر را با شناسه حذف می کند.
نحوه پیاده سازی ثبت نام و ورود به سیستم
در این بخش، یک سرویس احراز هویت ایجاد می کنیم که توکن های وب JSON (JWT) را تولید می کند.
این سرویس دو روش دارد: signup
و login
. signup
متد یک شی درخواست ثبت نام شامل name
، email
و
password
) و روش login
یک شی درخواست ورود به سیستم را می گیرد
حاوی email
و password
هر دو روش یک JWT برمی گرداند.
بیایید با ایجاد یک ماژول منبع برای APIهای احراز هویت شروع کنیم.
ایجاد منبع auth
با Nest CLI:
$ nest generate res auth
سپس DTO را هم برای ثبت نام و هم برای ورود تعریف کنید. به پوشه dto در پوشه src/auth/dto بروید:
signup.dto.ts :
export class SignUpDto { name: string; email: string; password: string; }
login.dto.ts :
export class Login { email: string; password: string; }
سپس یک فایل .env در دایرکتوری ریشه ایجاد کنید:
JWT_SECRET=secret JWT_EXPIRES=3d
سپس PassportModule
، JwtModule
و JwtStrategy
را به AuthModule
اضافه کنید. ما با نصب این بسته ها شروع می کنیم:
$ npm i @nestjs/passport @nestjs/jwt passport passport-jwt bcryptjs
به src/auth/auth.module.ts بروید و این بسته ها را وارد کنید:
import { Module } from '@nestjs/common'; import { AuthService } from './auth.service'; import { AuthController } from './auth.controller'; import { PassportModule } from '@nestjs/passport'; import { JwtModule } from '@nestjs/jwt'; import { ConfigModule, ConfigService } from '@nestjs/config'; import { MongooseModule } from '@nestjs/mongoose'; import { UserSchema } from 'src/users/entities/user.entity'; @Module({ imports: [ PassportModule.register({ defaultStrategy: 'jwt' }), JwtModule.registerAsync({ imports: [ConfigModule], inject: [ConfigService], useFactory: (config: ConfigService) => { return { secret: config.get<string>('JWT_SECRET'), signOptions: { expiresIn: config.get<string | number>('JWT_EXPIRES'), }, }; }, }), MongooseModule.forFeature([{ name: 'User', schema: UserSchema }]), ], controllers: [AuthController], providers: [AuthService], }) export class AuthModule {}
PassportModule.register
ماژول Passport را برای استفاده از استراتژی JWT به عنوان مکانیزم احراز هویت پیکربندی می کند.
JwtModule.registerAsync
ماژول JWT را با استفاده از فرآیند ثبت نام ناهمزمان، مانند زمان انقضای رمز، پیکربندی می کند.
MongooseModule.forFeature()
mongoose را برای ما UserSchema
برای مدل User
پیکربندی می کند.
این واردات، ماژول احراز هویت را قادر می سازد تا احراز هویت کاربر، تولید JWT و تعامل پایگاه داده را مدیریت کند.
سپس، AuthServices
برای ثبت نام ایجاد کنید و در دایرکتوری src/auth/auth.service.ts وارد شوید:
import { Injectable, UnauthorizedException} from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; import { InjectModel } from '@nestjs/mongoose'; import { Model } from 'mongoose'; import { User } from 'src/users/entities/user.entity'; import { SignUpDto } from './dto/signup.dto'; import * as bcrypt from 'bcryptjs'; import { LoginDto } from './dto/login.dto'; import { ConfigService } from '@nestjs/config'; @Injectable() export class AuthService { constructor( @InjectModel(User.name) private userModel: Model<User>, private jwtService: JwtService, private configService: ConfigService, ) {} async signUp(signupDto: SignUpDto) { const { name, email, password } = signupDto; const hashedPassword = await bcrypt.hash(password, 10); const user = await this.userModel.create({ name, email, password: hashedPassword, }); await user.save(); const token = await this.jwtService.sign( { id: user.id }, { secret: this.configService.get('JWT_SECRET'), expiresIn: this.configService.get('JWT_EXPIRES'), }, ); return { token }; } async login(loginDto: LoginDto) { const { email, password } = loginDto; const user = await this.userModel.findOne({ email, }); if (!user) throw new UnauthorizedException('invalid email or password'); const passwordMatch = await bcrypt.compare(password, user.password); if (!passwordMatch) throw new UnauthorizedException('invalid email or password'); const token = await this.jwtService.sign( { id: user.id }, { secret: this.configService.get('JWT_SECRET'), }, ); return { token }; } }
در AuthService
، روش signUp
ثبت نام کاربر را توسط:
تخریب شی SignupDto
برای استخراج اعتبار کاربر.
هش کردن رمز عبور با استفاده از bcrypt
برای ذخیره سازی ایمن.
ایجاد یک سند کاربر جدید در پایگاه داده از طریق userModel
.
ذخیره سند کاربر در پایگاه داده
تولید یک توکن JWT با استفاده از jwtService
پس از ثبت نام موفقیت آمیز.
بازگرداندن توکن JWT به مشتری.
روش login
احراز هویت کاربران را توسط:
تخریب شی LoginDto
برای تأیید اعتبار کاربر.
مقایسه رمز عبور ورودی با هش ذخیره شده برای اطمینان از مطابقت.
پرتاب خطای UnauthorizedException
در صورت عدم تطابق رمزهای عبور.
استفاده از jwtService
برای امضای کاربر و تولید توکن JWT پس از احراز هویت موفق.
بازگرداندن توکن JWT به مشتری.
AuthController
برای ثبت نام و ورود به دایرکتوری src/auth/auth.controller.ts به روز کنید:
import { Controller, Post, Body } from '@nestjs/common'; import { AuthService } from './auth.service'; import { SignUpDto } from './dto/signup.dto'; import { LoginDto } from './dto/login.dto'; @Controller('auth') export class AuthController { constructor(private readonly authService: AuthService) {} @Post('signup') signUp(@Body() signupDto: SignUpDto) { return this.authService.signUp(signupDto); } @Post('login') signin(@Body() loginDto: LoginDto) { return this.authService.login(loginDto); } }
با این مراحل، یک ورود و ثبت نام اولیه کاربر را در برنامه خود پیاده سازی کرده اید. در بخش های بعدی، مسیرهای login
و signup
را آزمایش خواهیم کرد.
تست در پستچی
اکنون که نقاط پایانی خود را تنظیم کردهایم، وقت آن است که آنها را آزمایش کنیم.
برای این مثال، من از Postman به عنوان مشتری API خود استفاده خواهم کرد، اما خیالتان راحت باشد
برای استفاده از هر ابزار یا مشتری متناسب با نیاز شما. بیایید API خود را در آن ببینیم
عمل!
نحوه ایجاد کاربر با /signup
Endpoint:
پس از ارسال درخواست POST به نقطه پایانی /signup با استفاده از Postman، ما
پاسخی حاوی AccessToken دریافت کرد. شما می توانید تأیید کنید که جدید است
کاربر با تحلیل پایگاه داده با موفقیت ایجاد شد.
به عنوان یک کاربر موجود با /login
endpoint وارد شوید:
نتیجه
تبریک می گویم، شما با موفقیت جامع را اجرا کردید
احراز هویت با استفاده از NestJS، Mongoose و Passport. ما یک امن طراحی کردیم
فرآیند ثبت نام و ورود به سیستم و ایجاد توکن های وب JSON (JWT).
برای بهبود بیشتر و گسترش دانش خود در مورد احراز هویت، نگاه کنید
به مجوز، محافظت از مسیرها با میان افزار احراز هویت،
و اجرای تایید ایمیل و قابلیت بازنشانی رمز عبور.
این پایه یک نقطه شروع محکم برای ساختن یک ساختمان قوی فراهم می کند
و سیستم احراز هویت مقیاس پذیر. این پروژه برای کار لذت بخش بود
در، و من امیدوارم که شما آن را به همان اندازه لذت بخش بود.
برای راحتی شما، مخزن پروژه در Github در دسترس است .
لطفاً در ارتباط با من در توییتر در Adedot1Abimbola@ تردید نکنید.
من دوست دارم از شما بشنوم
ارسال نظر