Nestjs项目实战 JWT认证机制的实现
在NestJS项目中实现JWT认证机制时遇到几个问题:
-
如何正确配置JWT模块?我在安装
@nestjs/jwt
后不太清楚如何在AppModule中进行注册,是否需要额外设置secretKey和过期时间? -
登录成功后生成的Token应该包含哪些标准字段?除了sub和iat之外,是否需要手动添加用户角色权限信息?
-
前端请求携带Token时,如何设计拦截器自动将Token注入Authorization头?现在每次手动添加感觉很不规范。
-
为什么我的Token验证守卫(@UseGuards)有时候会跳过验证?是不是和路由的顺序有关?
-
有没有推荐的安全存储JWT的方案?目前直接存localStorage担心XSS攻击,用httpOnly的Cookie又怕CSRF问题。
在NestJS中实现JWT认证机制非常方便。首先安装必要的依赖:
npm install [@nestjs](/user/nestjs)/jwt [@nestjs](/user/nestjs)/passport passport passport-jwt --save
-
配置Passport:创建一个Guard用于JWT验证。
import { Injectable } from '[@nestjs](/user/nestjs)/common'; import { AuthGuard } from '[@nestjs](/user/nestjs)/passport'; [@Injectable](/user/Injectable)() export class JwtAuthGuard extends AuthGuard('jwt') {}
-
创建JWT策略:
import { ExtractJwt, Strategy } from 'passport-jwt'; import { PassportStrategy } from '[@nestjs](/user/nestjs)/passport'; import { Injectable } from '[@nestjs](/user/nestjs)/common'; [@Injectable](/user/Injectable)() export class JwtStrategy extends PassportStrategy(Strategy) { constructor() { super({ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), ignoreExpiration: false, secretOrKey: 'your-secret-key', }); } async validate(payload: any) { return { userId: payload.sub, username: payload.username }; } }
-
实现登录逻辑并生成JWT:
import { Controller, Post, Body, Res } from '[@nestjs](/user/nestjs)/common'; import { AuthService } from './auth.service'; import { Response } from 'express'; [@Controller](/user/Controller)('auth') export class AuthController { constructor(private authService: AuthService) {} @Post('login') async login(@Body() userDto: { username: string; password: string }, @Res() res: Response) { const token = await this.authService.validateUser(userDto); if (token) { res.status(200).json({ token }); } else { res.status(401).send('Unauthorized'); } } }
-
服务层处理逻辑:
import { Injectable } from '[@nestjs](/user/nestjs)/common'; import * as bcrypt from 'bcrypt'; import { JwtService } from '[@nestjs](/user/nestjs)/jwt'; [@Injectable](/user/Injectable)() export class AuthService { constructor(private jwtService: JwtService) {} async validateUser(userDto: { username: string; password: string }): Promise<string | null> { // 模拟用户验证 if (userDto.username === 'test' && userDto.password === 'password') { const payload = { sub: 1, username: 'test' }; return this.jwtService.sign(payload); } return null; } }
-
保护路由:
import { Controller, Get, UseGuards } from '[@nestjs](/user/nestjs)/common'; import { JwtAuthGuard } from './guards/jwt-auth.guard'; [@Controller](/user/Controller)('profile') [@UseGuards](/user/UseGuards)(JwtAuthGuard) export class ProfileController { @Get() getProfile() { return { message: 'Protected route' }; } }
完成以上步骤后,你的NestJS应用就实现了基本的JWT认证功能。
在NestJS项目中实现JWT认证机制,主要分为生成Token、验证Token和拦截器保护路由三个步骤:
-
安装依赖:首先安装
[@nestjs](/user/nestjs)/jwt
和[@nestjs](/user/nestjs)/passport
以及passport-jwt
。命令如下:npm install [@nestjs](/user/nestjs)/jwt [@nestjs](/user/nestjs)/passport passport-jwt passport
-
配置JWT策略:创建一个JWT策略类,用于验证请求中的Token。
import { ExtractJwt, Strategy } from 'passport-jwt'; import { PassportStrategy } from '[@nestjs](/user/nestjs)/passport'; export class JwtStrategy extends PassportStrategy(Strategy) { constructor() { super({ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), ignoreExpiration: false, secretOrKey: 'your-secret-key', }); } async validate(payload: any) { return { userId: payload.sub, username: payload.username }; } }
-
生成Token:用户登录时生成Token并返回给客户端。
import { Injectable } from '[@nestjs](/user/nestjs)/common'; import { JwtService } from '[@nestjs](/user/nestjs)/jwt'; [@Injectable](/user/Injectable)() export class AuthService { constructor(private jwtService: JwtService) {} async login(user: any) { const payload = { username: user.username, sub: user.userId }; return { access_token: this.jwtService.sign(payload), }; } }
-
保护路由:使用
@UseGuards
装饰器结合JWTGuard来保护需要认证的路由。import { Controller, Get, UseGuards } from '[@nestjs](/user/nestjs)/common'; import { AuthGuard } from '[@nestjs](/user/nestjs)/passport'; [@Controller](/user/Controller)('protected') export class ProtectedController { @UseGuards(AuthGuard('jwt')) @Get() getProtectedData() { return { message: 'This is protected data' }; } }
通过以上步骤,就可以在NestJS项目中实现基本的JWT认证机制。记得根据实际需求调整秘钥和策略配置。
NestJS JWT认证机制实现
在NestJS中实现JWT(JSON Web Token)认证机制主要包括以下几个步骤:
1. 安装必要依赖
npm install @nestjs/jwt @nestjs/passport passport passport-jwt
npm install @types/passport-jwt --save-dev
2. 创建Auth模块
// auth/auth.module.ts
import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
import { AuthService } from './auth.service';
import { JwtStrategy } from './jwt.strategy';
@Module({
imports: [
JwtModule.register({
secret: 'your-secret-key', // 实际项目中应从配置读取
signOptions: { expiresIn: '60s' },
}),
],
providers: [AuthService, JwtStrategy],
exports: [AuthService],
})
export class AuthModule {}
3. 实现Auth服务
// auth/auth.service.ts
import { Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
@Injectable()
export class AuthService {
constructor(private readonly jwtService: JwtService) {}
async validateUser(username: string, pass: string): Promise<any> {
// 这里应实现实际用户验证逻辑
if (username === 'admin' && pass === 'password') {
return { userId: 1, username: 'admin' };
}
return null;
}
async login(user: any) {
const payload = { username: user.username, sub: user.userId };
return {
access_token: this.jwtService.sign(payload),
};
}
}
4. 实现JWT策略
// auth/jwt.strategy.ts
import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor() {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: 'your-secret-key', // 应与JwtModule中的一致
});
}
async validate(payload: any) {
return { userId: payload.sub, username: payload.username };
}
}
5. 创建保护路由的守卫
// auth/auth.guard.ts
import { Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {}
6. 在控制器中使用
// app.controller.ts
import { Controller, Post, Request, UseGuards } from '@nestjs/common';
import { AuthService } from './auth/auth.service';
import { JwtAuthGuard } from './auth/auth.guard';
@Controller()
export class AppController {
constructor(private authService: AuthService) {}
@Post('auth/login')
async login(@Request() req) {
return this.authService.login(req.user);
}
@UseGuards(JwtAuthGuard)
@Get('profile')
getProfile(@Request() req) {
return req.user;
}
}
注意事项
- 实际项目中应将密钥存储在环境变量中
- 考虑使用更复杂的用户验证逻辑
- 可以添加刷新令牌机制
- 考虑令牌失效处理
这就是在NestJS中实现JWT认证的基本流程。你可以根据需要扩展这个基础实现,添加更多功能如角色权限控制等。