Nestjs集成JWT实现无状态身份验证教程

在使用NestJS集成JWT进行无状态身份验证时遇到了几个问题:

  1. 如何正确配置JWT模块?官方文档的示例不太清晰
  2. 前端请求时Authorization头应该如何设置格式?Bearer token的具体实现方式是什么
  3. 为什么我的Token验证中间件总是返回401错误?已经检查过密钥是正确的
  4. 如何实现Token自动刷新机制?现有的access_token过期后该如何处理
  5. 在生产环境中应该如何安全地存储JWT_SECRET?目前是直接写在环境变量里
3 回复
  1. 安装依赖:npm install @nestjs/jwt @nestjs/passport passport passport-local bcryptjs
  2. 配置JWT模块,在 AppModule 中引入 JwtModule 并设置密钥。
  3. 创建 AuthModule,导入 PassportModule 和 JwtStrategy。
  4. 实现 JwtStrategy,使用 @Injectable() 装饰器,并注入 JwtService 和 ConfigService。
  5. 编写登录接口,验证用户信息后生成 JWT Token。
  6. 在需要认证的路由上使用 @UseGuards(JwtAuthGuard)
  7. 前端请求时携带 Authorization 头部,值为 Bearer <token>。

示例代码:

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor(private config: ConfigService) {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      ignoreExpiration: false,
      secretOrKey: config.get('JWT_SECRET'),
    });
  }

  async validate(payload: any) {
    return { userId: payload.sub, username: payload.username };
  }
}

这种方式使服务间通信无需保存用户状态,适合微服务架构。


要在NestJS中集成JWT实现无状态身份验证,可按以下步骤操作:

  1. 安装依赖

    npm install [@nestjs](/user/nestjs)/jwt [@nestjs](/user/nestjs)/passport passport passport-jwt jsonwebtoken
    
  2. 配置Passport和JWT模块: 在app.module.ts中引入JwtModule并配置秘钥:

    import { Module } from '[@nestjs](/user/nestjs)/common';
    import { JwtModule } from '[@nestjs](/user/nestjs)/jwt';
    
    [@Module](/user/Module)({
      imports: [
        JwtModule.register({
          secret: 'your-secret-key', // 替换为自己的密钥
          signOptions: { expiresIn: '60s' },
        }),
      ],
    })
    export class AppModule {}
    
  3. 创建Auth策略: 创建auth.strategy.ts文件:

    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 };
      }
    }
    
  4. 生成JWT令牌: 在登录接口中生成JWT:

    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),
        };
      }
    }
    
  5. 保护路由: 使用@UseGuards装饰器添加JWT认证:

    import { Controller, UseGuards, Request, Post, Body } from '[@nestjs](/user/nestjs)/common';
    import { AuthGuard } from '[@nestjs](/user/nestjs)/passport';
    
    [@Controller](/user/Controller)('auth')
    export class AuthController {
      @UseGuards(AuthGuard('jwt'))
      @Post('profile')
      getProfile(@Request() req) {
        return req.user;
      }
    }
    

完成以上步骤后,你就成功集成了JWT到NestJS项目中,可以实现无状态的身份验证了。

NestJS集成JWT实现无状态身份验证教程

1. 安装必要依赖

npm install @nestjs/jwt passport passport-jwt
npm install @types/passport-jwt --save-dev

2. 配置JWT模块

// auth.module.ts
import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
import { AuthService } from './auth.service';

@Module({
  imports: [
    JwtModule.register({
      secret: 'your_secret_key', // 替换为你的密钥
      signOptions: { expiresIn: '60s' }, // 令牌有效期
    }),
  ],
  providers: [AuthService],
  exports: [AuthService],
})
export class AuthModule {}

3. 创建认证服务

// auth.service.ts
import { Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';

@Injectable()
export class AuthService {
  constructor(private readonly jwtService: JwtService) {}

  async generateToken(user: any) {
    const payload = { username: user.username, sub: user.userId };
    return {
      access_token: this.jwtService.sign(payload),
    };
  }
}

4. 配置Passport策略

// 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', // 与JWT模块中的密钥一致
    });
  }

  async validate(payload: any) {
    return { userId: payload.sub, username: payload.username };
  }
}

5. 创建保护路由的守卫

// auth.guard.ts
import { Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';

@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {}

6. 使用示例

// 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 authService: AuthService) {}

  @Post('login')
  async login(@Request() req) {
    return this.authService.generateToken(req.user);
  }

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

7. 配置全局守卫(可选)

// main.ts
app.useGlobalGuards(new JwtAuthGuard());

这样你就完成了NestJS中JWT无状态身份验证的集成。客户端需要在请求头中添加Authorization: Bearer <token>来访问受保护的路由。

回到顶部