要在 NestJS 中配置 Passport 的 Local 策略,需要完成以下步驟。這包括創建策略、守衞和服務以處理用户驗證。
1. 安裝依賴包
首先,確保已經安裝必要的依賴包:
npm install @nestjs/passport passport passport-local
2. 創建 .env 文件
在項目根目錄下創建一個 .env 文件,並添加 JWT 相關的配置:
JWT_SECRET=your_jwt_secret_key
JWT_EXPIRES_IN=3600s
3. 配置 ConfigModule
在 app.module.ts 中導入並配置 ConfigModule:
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { AuthModule } from './auth/auth.module';
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true, // 設置為全局模塊
}),
AuthModule,
],
})
export class AppModule {}
4. 創建 Auth 模塊和服務
如果你還沒有創建 auth 模塊和服務,可以使用 Nest CLI 創建它們:
nest generate module auth
nest generate service auth
nest generate controller auth
5. 配置 JWT 模塊
在 auth.module.ts 中導入並配置 JWT 模塊,確保從 .env 文件中獲取配置:
導入和配置 Local, Jwt 策略和服務
// src/auth/auth.module.ts
import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
import { PassportModule } from '@nestjs/passport';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { LocalStrategy } from './local.strategy';
import { JwtStrategy } from './jwt.strategy';
@Module({
imports: [
PassportModule,
JwtModule.registerAsync({
// 確保 ConfigModule 被導入,這樣 ConfigService 可以在 useFactory 中使用。
// imports: [ConfigModule], // 如果在app.moudle.ts導入,且設置全局,此處可以省略
// 注入 ConfigService,這樣它可以在 useFactory 中使用。
inject: [ConfigService],
useFactory: async (configService: ConfigService) => ({
secret: configService.get<string>('JWT_SECRET'),
signOptions: { expiresIn: configService.get<string>('JWT_EXPIRES_IN') },
}),
}),
// 導入 ConfigModule 以便 AuthService 中可以使用 ConfigService,
// ConfigModule // 如果在app.moudle.ts導入,且設置全局,此處可以省略
],
providers: [AuthService, LocalStrategy, JwtStrategy],
controllers: [AuthController],
})
export class AuthModule {}
6. 創建 JWT 策略
創建一個 JwtStrategy 類來驗證 JWT 令牌:
// src/auth/jwt.strategy.ts
import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
import { ConfigService } from '@nestjs/config';
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(configService: ConfigService) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: configService.get<string>('JWT_SECRET'),
});
}
async validate(payload: any) {
return { userId: payload.sub, username: payload.username };
}
}
7. 創建 JwtAuthGuard 守衞
創建一個 JwtAuthGuard 類來保護需要進行 JWT 身份驗證的路由:
// src/auth/jwt-auth.guard.ts
import { Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {}
8. 創建 Local 策略
創建一個 LocalStrategy 類,它將負責用户驗證邏輯。放在 auth 目錄下:
// src/auth/local.strategy.ts
import { Strategy } from 'passport-local';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { AuthService } from './auth.service';
@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
constructor(private authService: AuthService) {
/**
* usernameField: 指定用户名字段的名稱,默認為 'username'。
* passwordField: 指定密碼字段的名稱,默認為 'password'。
* passReqToCallback: 如果設置為 true,request 對象將作為第一個參數傳遞給驗證函數。
*
* 如果你的請求中的用户名字段不是默認的 username,而是 account 或其他名稱,可以使用這個參數指定。
*/
super({ usernameField: 'account' });
}
async validate(account: string, password: string): Promise<any> {
const user = await this.authService.validateUser(username, password);
if (!user) {
throw new UnauthorizedException();
}
return user;
}
}
9. 創建 Local Auth 守衞
創建一個 LocalAuthGuard 類來保護需要進行本地身份驗證的路由:
// src/auth/local-auth.guard.ts
import { Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
@Injectable()
export class LocalAuthGuard extends AuthGuard('local') {}
10. 在 Auth 服務中實現用户驗證邏輯
在 auth.service.ts 中添加驗證用户的邏輯。這個服務將從數據庫或其他用户存儲中查找用户。
// src/auth/auth.service.ts
import { Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
@Injectable()
export class AuthService {
constructor(private readonly jwtService: JwtService) {}
async login(user: any) {
const payload = { username: user.username, sub: user.userId };
return {
access_token: this.jwtService.sign(payload),
};
}
async validateUser(username: string, pass: string): Promise<any> {
// 假設有一個用户驗證邏輯
const user = { userId: 1, username: 'test', password: 'test' }; // 這是一個示例用户
if (user && user.password === pass) {
const { password, ...result } = user;
return result;
}
return null;
}
}
11. 創建 Auth 控制器
創建一個控制器來處理登錄請求,並使用 LocalAuthGuard 進行保護:
// src/auth/auth.controller.ts
import { Controller, Post, Request, UseGuards } from '@nestjs/common';
import { AuthService } from './auth.service';
import { LocalAuthGuard } from './local-auth.guard';
@Controller('auth')
export class AuthController {
constructor(private readonly authService: AuthService) {}
@UseGuards(LocalAuthGuard)
@Post('login')
async login(@Request() req) {
return this.authService.login(req.user);
}
}
12. 保護路由
在需要保護的控制器中使用 JwtAuthGuard:
// src/protected/protected.controller.ts
import { Controller, Get, UseGuards } from '@nestjs/common';
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
@Controller('protected')
export class ProtectedController {
@UseGuards(JwtAuthGuard)
@Get()
getProtectedResource() {
return { message: 'This is a protected resource' };
}
}
完整示例結構
src/
auth/
auth.module.ts
auth.service.ts
auth.controller.ts
local.strategy.ts
local-auth.guard.ts
jwt.strategy.ts
jwt-auth.guard.ts
protected/
protected.controller.ts
測試流程
- 啓動 NestJS 應用程序。
- 使用 Postman 或類似工具發送 POST 請求到
/auth/login端點,提供正確的用户名和密碼。 - 獲取 JWT 令牌後,在請求受保護資源時在請求頭中添加
Authorization: Bearer <token>。
這樣,你就成功地在 NestJS 中配置了 Passport 的 Local 策略,並使用 JWT 進行身份驗證。