nestjs守卫/全局守卫校验jwt

一、守卫

目标

部分接口需要用户登录后才可以访问,用户登录后可以颁发 jwt_token 给前端,前端在调用需要鉴权的接口,需要在请求头添加 jwt_token,后端校验通过才能继续访问,否则返回403无权访问

创建守卫 anth

安装依赖
npm i @nestjs/jwt -S
配置 jwt 常量参数 constants/index.ts
// jwt秘钥,固定随机字符串
export const JWT_SECRET = "NODE_TEST_SECRET";

// jwt有效期 Eg: "60s", "3h", "2d"
export const JWT_EXPIRES = "2h"; // 2小时
创建 auth 模块 auth/auth.module.ts
import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
import { AuthService } from './auth.service';
import { JWT_SECRET, JWT_EXPIRES } from '../constants';

@Module({
  imports: [
    JwtModule.register({
      secret: JWT_SECRET, // jwt秘钥
      signOptions: {
        expiresIn: JWT_EXPIRES, // jwt有效期
      }
    })
  ],
  providers: [AuthService],
  exports: [AuthService]
})
export class AuthModule {}
创建 auth 服务 auth/auth.service.ts
import { Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';

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

  // 创建jwt_token
  async createToken(userInfo) {
    // 将用户信息(userId、name)存放到 jwt 中
    return {
      access_token: this.jwtService.sign(userInfo)
    };
  }

  // 校验登录状态
  validateToken(token) {
    if (!token) {
      return false;
    }
    try {
      return this.jwtService.verify(token);
    } catch {
      return false;
    }
  }
}
创建 auth 守卫 auth/auth.guard.ts
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { AuthService } from './auth.service';

@Injectable()
export class AuthGuard implements CanActivate {
  constructor(private authService: AuthService) {}

  canActivate(context: ExecutionContext) {
    const request = context.switchToHttp().getRequest();
    const token = request.headers['authorization']; // 从请求头中获取 token
    if (!token) {
      return false;
    } else {
      return this.authService.validateToken(token); // 如果 token 有效,返回 true,允许访问资源
    }
  }
}

使用守卫 auth

需要鉴权的模块添加 auth 模块

api.module.ts

...
import { AuthModule } from '../auth/auth.module';

@Module({
  imports: [AuthModule],
  ...
})
export class ApiModule {}
需要鉴权的接口引入守卫

api.controller.ts

...
import { Controller, Get, UseGuards } from '@nestjs/common';
import { AuthGuard } from '../auth/auth.guard';

@Controller('api')
export class ApiController {
  constructor(private readonly apiService: ApiService) {}

  @Get('getUserInfo')
  @UseGuards(AuthGuard) // 需要鉴权的接口添加UseGuards
  getUserInfo(): any {
    return this.apiService.getUserInfo();
  }
}
登录

调用 auth/auth.service.ts 中的 createToken 生成 jwt_token 返回给前端

前端在请求头添加 authorization

如果请求头没有 authorization,或者 authorization 失效,则返回 403 Forbidden

二、全局守卫

目标

由于单个守卫需要引入守卫模块、守卫方法,并且针对每一个接口加 @UseGuards 装饰器,使用起来比较繁琐。项目中经常遇到非常多的接口都需要鉴权,所以就需要使用全局守卫来校验需要鉴权的接口。

注意:获取与解析 jwt_token 的方法上面守卫的方法一致,auth/auth.service,此处不再赘述。

创建全局守卫

配置需要鉴权的接口常量 constants/index.ts
// 需要校验 jwt 的 url 列表
export const ValidUrlList = [
  '/api/getUserInfo',
  '/api/product/buy',
  '/api/queryUserWallet'
];
新建全局守卫 global.guard.ts
import { Injectable, NestInterceptor, ExecutionContext, HttpException, HttpStatus } from '@nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { AuthService } from './auth/auth.service';
import { ValidUrlList } from './constants';

@Injectable()
export class GlobalGuard implements NestInterceptor {
  constructor(private authService: AuthService) {}
  intercept(context: ExecutionContext, next): Observable<any> {
    // 在这里执行全局守卫逻辑
    const request = context.switchToHttp().getRequest();
    // 从请求头中获取 token
    const token = request.headers['authorization'];
    // 请求的url,用于判断是否需要校验jwt
    const url = request.url;
    if (ValidUrlList.includes(url)) {
      // 需要鉴权才能访问的接口
      const validRes = this.authService.validateToken(token);
      if (!validRes) {
        return next.handle().pipe(map(() => {
          // 如果没有提供令牌,返回错误响应或执行其他逻辑
          return new HttpException('Forbidden', HttpStatus.FORBIDDEN);
        }));
      }
    }
    // 不需要校验的接口、校验通过的接口直接放行
    return next.handle();
  }
}

在 app.module.ts 配置全局守卫

// ...
import { APP_INTERCEPTOR } from '@nestjs/core';
import { JwtModule } from '@nestjs/jwt';
import { GlobalGuard } from './global.guard';
import { JWT_SECRET, JWT_EXPIRES } from './constants';
import { AuthService } from './auth/auth.service';

@Module({
  imports: [
    JwtModule.register({
      secret: JWT_SECRET, // jwt秘钥
      signOptions: {
        expiresIn: JWT_EXPIRES, // jwt有效期
      }
    }),
  ],
  providers: [
    {
      provide: APP_INTERCEPTOR,
      useClass: GlobalGuard,
    },
    AuthService
  ],
})
export class AppModule {}

三、swagger文档调用需要鉴权的接口

接口添加 jwt 鉴权后,swagger接口文档调用接口请求头没有添加 authorization,请求会返回403。接口文档调用鉴权接口见另一篇博客 nestjs swagger文档调用需要鉴权的接口-CSDN博客

  • 18
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
@nestjs/jwt是一个用于在NestJS应用程序中实现JSON Web Token(JWT)功能的模块。您可以通过运行命令`npm i --save @nestjs/jwt`来安装它。然后,您可以在您的应用程序中导入JwtModule并在其配置中指定一个密钥,如以下代码所示: ```typescript import { Module } from '@nestjs/common'; import { JwtModule } from '@nestjs/jwt'; @Module({ imports: [JwtModule.register({ secret: 'hard-to-guess_secret' })], providers: [...], }) export class AuthModule {} ``` 这样,您就可以在您的应用程序中使用@nestjs/jwt模块提供的功能了。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [jwt:基于jsonwebtoken包的JWT实用程序模块:unlocked:](https://download.csdn.net/download/weixin_42114046/15243990)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [如何在 NestJS 中实现 JWT 认证](https://blog.csdn.net/weixin_47967031/article/details/127347203)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值