Nestjs使用cookie、session

1,361 阅读3分钟

Cookie

基本使用

  1. 安装依赖
pnpm add cookie-parser
pnpm add -D @types/cookie-parser
  1. main.ts 注入中间件
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import * as cookieParser from 'cookie-parser';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  // 解析cookie
  app.use(cookieParser());

  await app.listen(3000);
}
bootstrap();
  1. 获取与设置 cookie
import { Controller, Get, Req, Res } from '@nestjs/common';
import { AppService } from './app.service';
import { Request, Response } from 'express';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get()
  getHello(
    @Req() req: Request,
    @Res({ passthrough: true }) res: Response,
  ): string {
    // 1.从req中获取客户端请求的cookie
    console.log(
      '🚀 ~ file: app.controller.ts:11 ~ AppController ~ getHello ~ req:',
      req.cookies,
    );

    // 2.给客户端设置cookie
    const expiryDate = new Date(Date.now() + 10000); // 设置过期时间为当前时间往后 10 秒
    res.cookie('foo', 'bar', { expires: expiryDate });

    return this.appService.getHello();
  }
}

封装装饰器

  1. 创建装饰器
nest g d decorators/cookies
  1. 封装装饰器
import { ExecutionContext, createParamDecorator } from '@nestjs/common';
import { Request } from 'express';

export const Cookies = createParamDecorator(
  (data: string, ctx: ExecutionContext) => {
    const req = ctx.switchToHttp().getRequest() as Request;
    return data ? req.cookies?.[data] : req.cookies;
  },
);
  1. 使用
  @Get()
  getHello(@Cookies('foo') name: string): string {
    console.log(
      '🚀 ~ file: app.controller.ts:15 ~ AppController ~ name:',
      name,
    );
    return this.appService.getHello();
  }
  • 使用 curl 测试
curl -b "foo=bar" http://localhost:3000/

cookie的配置项

domain	  String	指定域名下有效
expires	  Date	        过期时间(秒),设置在某个时间点后会在该cookoe后失效
httpOnly    Boolean	默认为false表示不允许客户端(通过js来获取cookie)
maxAge	  String	最大失效时间(毫秒),设置在多少时间后失效
path	  String	表示cookie影响到的路径,如:path=/如果路径不能匹配的时候,浏览器则不发送这个cookie
secure	  Boolean	当 secure 值为 true 时,cookie 在 HTTP 中是无效,在 HTTPS 中才有效
signed	  Boolean	表示是否签名cookie,如果设置为true的时候表示对这个cookie签名了,需要用res.signedCookies()获取值

加密cookie

  1. main.ts 中加密
  • codersx 为加密字段
  • 加密需要给客户端返回的 cookie 添加 signed:true
import * as cookieParser from 'cookie-parser';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  // secret为codersx 加密
  app.use(cookieParser('codersx'));
  await app.listen(3000);
}
bootstrap();
  1. 获取/设置加密的 cookie
  @Get()
  getHello(
    @Req() req: Request,
    @Res({ passthrough: true }) res: Response,
  ): string {
    // 1.加密的cookie获取方式
    console.log(
      '🚀 ~ file: app.controller.ts:19 ~ AppController ~ req.signedCookies:',
      req.signedCookies.username,
    );

    // 2.给客户端设置加密cookie signed为true
    // 设置过期时间为当前时间往后10分钟
    const expiryDate = new Date(Date.now() + 1000 * 60 * 10); 
    res.cookie('username', 'codersx', {
      expires: expiryDate,
      // maxAge: 10000,
      httpOnly: true,
      signed: true,
    });
    return req.cookies.username;
  }

Session

session 是服务器 为每个用户的浏览器创建的一个会话对象,这个session 会记录到 浏览器的 cookie 用来区分用户

  1. 安装
pnpm add express-session
pnpm add -D @types/express-session
  1. session 的配置
  • secret: 必需的配置项,用于加密和签名会话数据的密钥。你应该使用一个安全的随机字符串作为密钥。

  • resave: 控制是否在每个请求中重新保存会话数据。设置为 false 表示只有在会话数据发生更改时才会保存,默认为 true

  • saveUninitialized: 控制是否在初始化期间保存未修改的会话。设置为 false 表示只有在会话数据发生更改时才会保存,默认为 true

  • name: 指定会话 cookie 的名称,默认为 "connect.sid"。

  • cookie: 设置会话 cookie 的选项,例如:

    • maxAge: 设置 cookie 的过期时间(以毫秒为单位)。
    • secure: 控制是否只通过 HTTPS 发送 cookie。
    • httpOnly: 控制是否只能通过 HTTP 访问 cookie,禁止客户端 JavaScript 访问。
    • domain: 设置 cookie 的域名。
    • path: 设置 cookie 的路径。
  1. main.ts 导入注册中间件
import * as session from 'express-session';

async function bootstrap() {
  //配置session
  app.use(
    session({
      secret: 'codesx',
      name: 'sx.session',
      rolling: true,
      cookie: { maxAge: null },
    }),
  );

  await app.listen(3000);
}
bootstrap();
  1. 使用示例
import { Controller, Get, Req, Session } from '@nestjs/common';
import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get()
  getHello(@Req() req: any): string {
    // 设置session
    req.session.name = 'codersx';
    return req.session;
  }

  @Get('/session')
  // 可以使用@Session()获取session或者req获取
  getSession(@Req() req, @Session() session: Record<string, any>): string {
    console.log(
      '🚀 ~ file: app.controller.ts:15 ~ AppController ~ session:',
      req.session,
    );
    console.log(
      '🚀 ~ file: app.controller.ts:26 ~ AppController ~ getSession ~ session.username:',
      req.session.name,
    );
    console.log(
      '🚀 ~ file: app.controller.ts:17 ~ AppController ~ getSession ~ session:',
      session,
    );

    return req.session.name;
  }
}