NestJS 使用 JWT 进行认证的流程是怎样的?

我在学习NestJS的JWT认证流程时遇到了一些疑问:

  1. 如何在NestJS中正确配置JWT模块?需要安装哪些依赖包?

  2. 生成JWT令牌时应该包含哪些必要的信息?如何设置合理的过期时间?

  3. 在实际项目中,应该把令牌存储在什么地方更安全?cookie还是localStorage?

  4. 如何实现令牌的自动刷新机制?当令牌快过期时怎样处理比较合理?

3 回复

在NestJS中实现JWT认证,通常包括以下步骤:

  1. 安装依赖:首先需要安装@nestjs/jwt@nestjs/passport等库。

  2. 配置Passport:使用Passport中间件处理JWT认证逻辑。

  3. 创建认证模块

    • 定义用户Schema和服务。
    • 创建登录接口,验证用户信息后生成JWT令牌。
  4. 生成JWT令牌:使用jsonwebtoken库,根据用户信息生成包含exp(过期时间)和sub(用户ID)的JWT。

  5. 解析JWT:在请求头中添加Authorization: Bearer <token>,通过装饰器自动解析并验证JWT。

  6. 保护路由:使用@UseGuards(JwtAuthGuard)装饰器保护需要认证的路由。

示例代码:

// JwtStrategy.ts
import { Strategy, ExtractJwt } from 'passport-jwt';
import { PassportStrategy } from '@nestjs/passport';
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor() {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      secretOrKey: 'your-secret-key',
    });
  }
  async validate(payload: any) {
    return { userId: payload.sub, username: payload.username };
  }
}

完整流程包括用户登录、生成JWT、设置过期时间和路由保护。


NestJS 使用 JWT 进行认证的流程如下:

  1. 安装依赖:首先需要安装必要的模块,如 [@nestjs](/user/nestjs)/jwt[@nestjs](/user/nestjs)/passport,以及 passport-jwt

    npm install [@nestjs](/user/nestjs)/jwt [@nestjs](/user/nestjs)/passport passport-jwt jsonwebtoken --save
    
  2. 配置 Passport:创建一个 auth.strategy.ts 文件,使用 PassportStrategy 实现 JWT 的验证逻辑。配置 jwtFromRequest 提取 token,验证签名。

  3. 生成 Token:用户登录时,后端验证用户名和密码,若正确则生成 JWT 并返回给前端。

    const payload = { username: user.username, sub: user.id };
    const token = this.jwtService.sign(payload);
    return { access_token: token };
    
  4. 保护路由:使用 @UseGuards(JwtAuthGuard) 装饰器来保护需要认证的路由。JwtAuthGuard 会自动验证请求中的 token。

  5. 前端存储 Token:前端接收到 token 后,通常存储在 localStoragecookie 中,并在每次请求时添加到 Authorization 头中。

  6. 刷新 Token(可选):为了解决 Token 过期问题,可以实现 Token 刷新机制,通过刷新 Token 获取新的访问 Token。

整个流程基于 JWT 的无状态特性,简化了服务器端的用户状态管理。

NestJS 中 JWT 认证的标准流程如下:

  1. 安装依赖
npm install @nestjs/jwt passport-jwt
npm install @types/passport-jwt -D
  1. 配置 JWT 模块 (auth.module.ts)
@Module({
  imports: [
    JwtModule.register({
      secret: 'your-secret-key', // 实际生产环境建议使用环境变量
      signOptions: { expiresIn: '60s' },
    }),
  ],
  providers: [AuthService],
})
export class AuthModule {}
  1. 创建认证服务 (auth.service.ts)
@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),
    };
  }
}
  1. 创建策略 (jwt.strategy.ts)
@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 };
  }
}
  1. 创建守卫 (jwt-auth.guard.ts)
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {}
  1. 控制器中使用 (auth.controller.ts)
@Controller('auth')
export class AuthController {
  constructor(private authService: AuthService) {}

  @Post('login')
  async login(@Body() loginDto: any) {
    return this.authService.login(loginDto);
  }

  @UseGuards(JwtAuthGuard)
  @Get('profile')
  getProfile(@Request() req) {
    return req.user;
  }
}

使用流程:

  1. 客户端发送登录请求获取 JWT token
  2. 后续请求在 Authorization header 携带 Bearer token
  3. 服务器验证 token 并提取用户信息

注意:

  • 实际项目中应使用环境变量管理密钥
  • 建议添加 refresh token 机制
  • 密码应使用 bcrypt 等库加密存储
回到顶部