神光《Nest 通关秘籍》学习总结–在Nest中如何实现session和jwt

最近在学习神光大神的《Nest通关秘籍》,接下来的日子里,我将更新一系列的学习笔记。

感兴趣的可以关注我的专栏《Nest 通关秘籍》学习总结

特别申明:本系列文章已经经过作者本人的允许。
大家也不要想着白嫖,此笔记只是个人学习记录,不是非常完善,如想深入学习可以去购买原版小册,购买链接点击《传送门》。

本章我们来学习一下如何在Nest中实现session和jwt鉴权。

1. 创建项目

首先用 @nest/cli 快速创建一个 Nest.js 项目

nest new jwt-and-session -p npm

2. session + cookie 的实现

安装 express-session 和它的 ts 类型定义:

pnpm install express-session @types/express-session

然后在入口模块里启用它:

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import * as session from 'express-session';
async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.use(
    session({
      secret: 'xiumubai',
      resave: false,
      saveUninitialized: false,
    }),
  );
  await app.listen(3000);
}
bootstrap();
  • 指定加密的密钥 secret。
  • resave 为 true 是每次访问都会更新 session,不管有没有修改 session 的内容,而 false 是只有 session 内容变了才会去更新 session。
  • saveUninitalized 设置为 true 是不管是否设置 session,都会初始化一个空的 session 对象。比如你没有登录的时候,也会初始化一个 session 对象,这个设置为 false 就好。

在 controller 里就可以注入 session 对象:

@Get('sss')
sss(@Session() session) {
    console.log(session)
    session.count = session.count ? session.count + 1 : 1;
    return session.count;
}

在 session 里放了个 count 的变量,每次访问加一,然后返回这个 count。

运行项目:

npm run start:watch

然后用 apifox 测试下:

当每次发送一个请求的时候count都会+1.

而且返回了一个 cookie 是 connect.sid,这个就是对应 session 的 id。

因为 cookie 在请求的时候会自动带上,就可以实现请求的标识,给 http 请求加上状态。

3. jwt的实现

安装包:

pnpm install @nestjs/jwt

然后在 AppModule 里引入 JwtModule:

import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [
    JwtModule.register({
      secret: 'xiumubai',
      signOptions: {
        expiresIn: '7d',
      },
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

指定 secret,也就是加密 jwt 的密钥,还有 token 过期时间 expiresIn,设置 7 天。

然后在 controller 里注入 JwtModule 里的 JwtService,然后添加一个handler方法:

import { Controller, Get, Inject, Session, Res } from '@nestjs/common';
import { AppService } from './app.service';
import { JwtService } from '@nestjs/jwt';
import { Response } from 'express';
@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Inject(JwtService)
  private jwtService: JwtService;


  @Get('ttt')
  ttt(@Res({ passthrough: true }) response: Response) {
    const newToken = this.jwtService.sign({
      count: 1,
    });

    response.setHeader('authorization', 'bearer ' + newToken);
    return 'hello';
  }

}

这里使用 jwtService.sign 来生成一个 jwt token,放到 response header 里。

然后我们在apifox中访问一下看看:

可以看到,返回的响应确实带上了这个 header。

现在我们再加一些逻辑,如果后端接受请求的时候拿到了authorization,那就把它取出来,然后 +1 之后再放回去:

import {
  Controller,
  Get,
  Inject,
  Session,
  Res,
  Headers,
  UnauthorizedException,
} from '@nestjs/common';
import { AppService } from './app.service';
import { JwtService } from '@nestjs/jwt';
import { Response } from 'express';
@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Inject(JwtService)
  private jwtService: JwtService;

  @Get()
  getHello(): string {
    return this.appService.getHello();
  }

  @Get('ttt')
  ttt(
    @Headers('authorization') authorization: string,
    @Res({ passthrough: true }) response: Response,
  ) {
    if (authorization) {
      try {
        const token = authorization.split(' ')[1];
        const data = this.jwtService.verify(token);

        const newToken = this.jwtService.sign({
          count: data.count + 1,
        });
        response.setHeader('authorization', 'bearer ' + newToken);
        return data.count + 1;
      } catch (e) {
        console.log(e);
        throw new UnauthorizedException();
      }
    } else {
      const newToken = this.jwtService.sign({
        count: 1,
      });
      response.setHeader('authorization', 'bearer ' + newToken);
      return 1;
    }
  }
}

通过 @Headers 装饰器取出 autorization 的 header,然后通过 jwtService.verify 对它做验证。

如果验证失败,那就抛出 UnauthorizedException 异常,让 Nest 内置的 Exception Filter 来处理。

验证成功就重新生成 jwt 放到 header 里返回。

如果没有 autorization 的 header,那就生成一个 jwt 放到 header 里返回。

下面我们测试一下:

第一次访问:

响应为1,返回一个token,复制下来。

第二次访问:

请求头带着复制的token值

响应为2,然后返回了一个新的token。

第三次访问,重复1,2步骤。

这就是通过 jwt 保存状态的方式。

当然,一般正常开发中,前端会保存一个token,然后请求的时候传给后端,后端去校验这个token,如果没有问题,就会通过请求。如果有问题,就会重新登录,然后生成一个新的token。

如果这里我们传一个错误的token值:

这时候 jwtService.verify 方法就会抛异常,然后我们返回了 401 错误。

这样,我们就分别用 Nest 分别实现了 session + cookie 和 jwt 两种保存 http 状态的方式。

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYGgGD2X' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片