PassportJS — asoslar va strategiyalar
Muammodan boshlaylik
Foydalanuvchi kirish uchun email va parol yubordi. Siz tekshirasiz — to'g'ri. Keyingi so'rovda esa kim ekanini qaerdan bilasiz? HTTP — stateless, har so'rov mustaqil. Server oldingi so'rovni "eslamaydi".
Bundan tashqari, keyinroq Google orqali kirish qo'shish kerak bo'ldi. Keyin Facebook. Keyin telefon raqami bilan. Har biri uchun alohida mantiq — kod takrorlanadi, xatolar ko'payadi.
PassportJS bu ikki muammoni hal qiladi: kim ekanini tekshirish mexanizmi (strategiya) va NestJS bilan ulanish (integratsiya).
PassportJS nima?
Passport — Node.js uchun autentifikatsiya middleware kutubxonasi. U 500+ "strategiya" ni qo'llab-quvvatlaydi: email/parol, JWT, Google, GitHub, Facebook va boshqalar.
Hayotiy o'xshatma: aeroportdagi pasport nazorati. Bir xil nazorat punkti turli pasportlarni tekshiradi — O'zbekiston, Rossiya, AQSh. Qaysi pasport bo'lishidan qat'i nazar, nazorat bir xil: "bu hujjat haqiqiymi? Bu odam kim?" PassportJS ham shunday — bir xil interfeys, turli tekshiruv usullari.
O'rnatish
npm install @nestjs/passport passport passport-local
npm install -D @types/passport-local
Autentifikatsiya uchun alohida modul yaratamiz:
src/
└── auth/
├── auth.module.ts
├── auth.service.ts
├── auth.controller.ts
├── strategies/
│ └── local.strategy.ts ← email/parol strategiyasi
└── guards/
└── local-auth.guard.ts ← strategiyani ishlatuvchi guard
Local Strategiya — email va parol
// src/auth/strategies/local.strategy.ts
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { Strategy } from 'passport-local';
import { AuthService } from '../auth.service';
@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
constructor(private authService: AuthService) {
super({
usernameField: 'email', // standart 'username' o'rniga 'email'
});
}
// Passport bu metoddan foydalanuvchi topilsa qaytaradi,
// topilmasa UnauthorizedException tashlaydi
async validate(email: string, password: string) {
const user = await this.authService.validateUser(email, password);
if (!user) {
throw new UnauthorizedException('Email yoki parol noto\'g\'ri');
}
return user; // ← req.user ga qo'yiladi
}
}
PassportStrategy(Strategy) — bu NestJS va Passport o'rtasidagi ko'prik. validate metodi Passport tomonidan chaqiriladi — siz faqat ichini yozasiz.
Auth Service — foydalanuvchini tekshirish
// src/auth/auth.service.ts
import { Injectable } from '@nestjs/common';
import { UsersService } from '../users/users.service';
import * as bcrypt from 'bcrypt';
@Injectable()
export class AuthService {
constructor(private usersService: UsersService) {}
async validateUser(email: string, password: string) {
const user = await this.usersService.findByEmail(email);
if (!user) return null;
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) return null;
// Parolni olib tashlash — req.user da parol bo'lmasin
const { password: _, ...result } = user.toObject();
return result;
}
}
{ password: _, ...result } — destructuring bilan parolni olib tashlaymiz. _ — bu qiymat kerak emas degani (konvensiya).
Local Guard — strategiyani ishlatish
// src/auth/guards/local-auth.guard.ts
import { Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
@Injectable()
export class LocalAuthGuard extends AuthGuard('local') {}
// 'local' — LocalStrategy da register qilingan nom
Auth Module — hammasini birlashtirish
// src/auth/auth.module.ts
import { Module } from '@nestjs/common';
import { PassportModule } from '@nestjs/passport';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { LocalStrategy } from './strategies/local.strategy';
import { UsersModule } from '../users/users.module';
@Module({
imports: [
PassportModule,
UsersModule, // ← UsersService ishlatish uchun
],
providers: [AuthService, LocalStrategy],
controllers: [AuthController],
exports: [AuthService],
})
export class AuthModule {}
Controller — login endpoint
// src/auth/auth.controller.ts
import { Controller, Post, UseGuards, Req } from '@nestjs/common';
import { LocalAuthGuard } from './guards/local-auth.guard';
@Controller('auth')
export class AuthController {
// POST /auth/login
@Post('login')
@UseGuards(LocalAuthGuard) // ← Passport email/parol tekshiradi
login(@Req() req) {
// LocalStrategy validate() muvaffaqiyatli bo'lsa
// req.user = validate() dan qaytgan ob'ekt
return req.user;
}
}
So'rov oqimi:
POST /auth/login { email, password }
│
▼
LocalAuthGuard ishga tushadi
│
▼
LocalStrategy.validate(email, password)
│
▼
AuthService.validateUser(email, password)
│ ✓ to'g'ri → user ob'ekti
▼
req.user = user
│
▼
Controller.login(req) → req.user qaytariladi
UsersService ga findByEmail qo'shish
// src/users/users.service.ts
async findByEmail(email: string) {
// select('+password') — schema da select: false bo'lgan parolni olish
return this.userModel
.findOne({ email, deletedAt: null })
.select('+password')
.exec();
}
Strategiyalarni tushunish — muhim nuqta
Passport ning kuchi — bir xil interfeys, har xil strategiyalar:
LocalStrategy → email + parol tekshiradi
JwtStrategy → JWT token tekshiradi
GoogleStrategy → Google OAuth tekshiradi
GithubStrategy → GitHub OAuth tekshiradi
Har strategiya:
- So'rovdan kerakli ma'lumotni oladi (email/parol, token, code...)
validate()metodida tekshiradi- Muvaffaqiyatli bo'lsa
req.userga qo'yadi
Keyingi darsda JWT strategiyasini qo'shamiz — login da token beramiz, keyin har so'rovda shu token tekshiriladi.
Tez-tez uchraydigan xatolar
usernameField unutish
// ❌ Standart — Passport 'username' maydonini qidiradi
super();
// ✅ Email ishlatayotgan bo'lsangiz
super({ usernameField: 'email' });
UsersModule ni export qilmaslik
// ❌ AuthModule da UsersService ko'rinmaydi
@Module({
providers: [UsersService], // exports yo'q
})
export class UsersModule {}
// ✅
@Module({
providers: [UsersService],
exports: [UsersService], // ← AuthModule ishlatishi uchun
})
export class UsersModule {}
req.user bo'sh kelishi
Agar validate() null qaytarsa yoki xato tashlasa — Passport 401 Unauthorized qaytaradi, controller ga yetib bormaydi. Bu to'g'ri xatti-harakat.
Xulosa
PassportJS — autentifikatsiya strategiyalarini standart interfeys orqali boshqarish. Har strategiya validate() metodini implement qiladi.
Eslab qoling:
PassportStrategy(Strategy)— NestJS uchun ko'prikvalidate()— Passport chaqiradi, siz mantiq yozasizAuthGuard('nom')— strategiyani faollashtiradireq.user—validate()dan qaytgan ob'ektusernameField: 'email'— standartusernameo'rniga
Keyingi dars
26-dars: JWT Authentication — Access Token