LoginSignup
13
5

More than 1 year has passed since last update.

NestJSでCookieを利用する

Last updated at Posted at 2022-01-22

これはなに?

業務でCookieを用いた実装することがあったので備忘録として書きました。

記事の下の方ではSet-Cookieの各属性について説明したのでCookieを調べている方の一助になれば幸いです。

この記事のゴール

以下の理解が得られることをゴールとします

  • NestJSでリクエストからCookieを取得できること
  • NestJSでレスポンスにCookieを詰められること
  • Set-Cookieの各属性について理解できること

手順

0. NestJSの導入

導入がまだの方は以前書いたこちらの記事を参考にしてもらえると理解が早いと思います。

1. cookie-parserの導入

今回は公式でも書かれているcookie-parserを利用します。

2022年1月時点で最新のものを利用しています。

パッケージ名 バージョン
cookie-parser v1.4.6
@types/cookie-parser v1.4.2
$ npm i cookie-parser
$ npm i -D @types/cookie-parser

2. ルートモジュールに適用する

ルートモジュールにcookieを利用できるように記載します。

公式では以下のように書かれています。

NestJS公式ドキュメント
import * as cookieParser from 'cookie-parser';
// somewhere in your initialization file
app.use(cookieParser());

今回NestJSのプロジェクトでは以下のように書きました。

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)
  app.use(cookieParser())
  await app.listen(3000)
}
bootstrap()

3. リクエストでcookieを取得する

app.controller.ts
import { Controller, Get, Req } from '@nestjs/common'
import { AppService } from './app.service'
import { Request } from 'express'

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

  @Get('/')
  getHello(
    @Req() request: Request,
  ): string {
    console.log('cookie: ', request.cookies)
    return this.appService.getHello()
  }
}
出力
cookie:  [Object: null prototype] {}

もちろんなにも設定していないのでcookieの中身は何もありません

4. Cookieに任意の値を設定する

app.controller.ts
import { Controller, Get, Req, Res } from '@nestjs/common'
import { AppService } from './app.service'
import { Response } from 'express'

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

  @Get('/')
  getHello(@Res({ passthrough: true }) response: Response): string {
    response.cookie('key', 'value', {
      signed: false,
      expires: new Date('2022-12-31'),
      httpOnly: true,
      path: '/',
      domain: 'localhost',
      secure: true,
      sameSite: 'lax',
    })
    return this.appService.getHello()
  }
}

出力
cookie:  { key: 'value' }

スクリーンショット 2022-01-22 14.26.13.png

今回はkeyにkey、valueにvalueを設定しました。
出力結果から分かるように設定されていることがわかります。

response.cookie('key', 'value', options)の部分で実際にCookieを設定しています。
singed, expires...等々ありますがそこはoptionsの設定になります。

optionsは以下の記事を参考にしながら設定しました。

optionsの各属性の説明は以下になります。

maxAge
型: number

  • Cookieの有効期限を秒数で表している
    • Set-Cookieの仕様では秒数だが、実際に指定する際はミリ秒なので注意が必要
  • 負の数値だった場合は即時期限切れになる
  • 下でも登場するexpiresと両方設定されている場合はmaxAgeが優先される

signed
型: boolean

  • 署名付きCookieを利用するかどうかを設定可能
  • 利用する場合はcookieParser()にsecretを設定する必要がある

expires
型: Date

  • Cookieの有効期限を日時タイムスタンプで表している。
  • 指定されなかった場合はセッションと同じ有効期限になる

httpOnly
型: boolean

  • HTTPテキスト内のスクリプトでCookieにアクセスできなくするもの
  • これによってサイトがXSSの脆弱性を持っていても、Cookieの流出を防ぐことができる

path
型: string

  • Cookieを送信するパスの条件
  • 上で記載した例だと/をpathに含んだページ(同じドメイン内でほぼ全てのページ)に対してCookieが送信される
  • /docsと設定するとhogehoge.com/docs以下のページにのみCookieが送信される

domain
型: string

  • Cookieの送信先を設定できる
  • 指定されなかった場合は自動的に現在のURLのホスト名が入る

secure
型: boolean

  • HTTPS通信でのみCookieを送信する
  • 安全でないサイト(http:)との通信を防ぐ役割をしている

encode
型: ((val: string) => string)

  • valueで設定した値をどのようにエンコードするかを設定できる

sameSite
型: boolean | "lax" | "strict" | "none"

  • 他のドメインへのリクエストを送る際にCokieの情報を付与するかどうかを設定できる
    • strictでは付与しない
    • laxではGETメソッドであれば付与される
    • noneでは全てのリクエストに付与する
  • これによりCSRFのような脆弱性を生むのを防ぐことができる

余談

全然関係ないのですが昨日参加したQiitaアドベントカレンダーのイベントでちょまどさんの言っていた「記事を書くことが恩返しになると思っている」と言うのを聞いてすごい良い考えだなと思いました。

自分じゃどうしようもない課題に直面した際に、調べて出てきた記事は全て救世主みたいですもんね。

そんな風に困っている誰かのためになれれば良いなと言うモチベーションで来週も書いていこうと思います。

ではまた!

参考記事

13
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
5