Cookieと認証(発展)
HTTPヘッダ
HTTPにおけるリクエストとレスポンスには、ヘッダと呼ばれるKey-Value型のデータ構造が毎回付加されています。Chromeの開発者ツールでのNetwork
タブで確認できるので、確認してみましょう。
Cookie
レスポンスヘッダにset-cookie
ヘッダを含めることにより、次回以降のリクエストで、クライアントはそのデータをリクエストヘッダのcookie
ヘッダに入れて毎回送信します。この性質を利用することで、HTTPサーバーはクライアント毎に異なるサービスを提供できるようになります。
Cookie自体もKey-Valueのデータ構造となっているので、set-cookie
ヘッダを複数回送信することにより、複数のcookieを1つのレスポンスで送信することができます。例として、Yahoo! Japanのウェブサイトにアクセスした際に、Yahoo! Japanが送信するCookieの中身を覗いてみましょう。
このレスポンスヘッダを受けて、ブラウザは次のようなCookieを保存します。
ブラウザを更新することで、設定されたCookieが確かにリクエストヘッダの中に含まれて送信されていることがわかります。
ExpressでCookieを利用する
Expressを用いてレスポンスヘッダにCookieを付加するには、express.Response#cookie
メソッドを利用します。また、クライアントからのリクエストのcookie
ヘッダを解析するためには、cookie-parserパッケージを利用します。
npm install cookie-parser
を実行して、パッケージをインストールしましょう。Webサーバーのプログラムは次のようになります。
import express from "express";
import cookieParser from "cookie-parser";
const app = express();
app.use(cookieParser());
app.get("/", (request, response) => {
// Cookieの値は文字列なので数値に変換が必要
const count = parseInt(request.cookies.count) || 0;
const newCount = count + 1;
// 変更後の値をレスポンスヘッダに乗せる
response.cookie("count", newCount.toString());
response.send(`${newCount}回目のアクセスですね。`);
});
app.listen(3000);
express.Request#cookies
プロパティには、ブラウザから送信されていたCookieがオブジェクト形式で保存されています。ブラウザで表示させると、更新ボタンが押されるたびに数値が増えていることがわかります。
プログラムの流れを整理すると、次の図のようになります。
演習
- Chromeの開発者ツールを用いて、リクエストヘッダとレスポンスヘッダの内容を確認してみましょう。
- シークレットモードでページを開くと値はどうなるでしょうか。
Cookieを用いた認証
ユーザー名とパスワードを用いて認証するタイプのアプリケーションを考えてみましょう。ユーザー名とパスワードを、そのままCookieに入れてしまうと、データが悪意のある第三者に奪われてしまうリスクが高まります。
このため、ログインが成功したタイミングで、クライアントに対してランダムなIDを発行し、Cookieに保存させておくことが一般的です(セッションIDと呼ばれる)。次回以降のアクセスでは、このセッションIDを用いて認証を行います。このフローを図にすると、次のようになります。
演習
ユーザーが自分のユーザー名とパスワードでログインし、プロフィールを表示できるウェブアプリケーションを作成してみましょう。
schema.prisma
は次の通りとします。
model User {
id Int @id @default(autoincrement())
username String @unique
password String
}
model Session {
id String @id // 一意でランダムなID
userId Int // UserのID
}