要在 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
进行身份验证。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。