Node.js の Express と docker で立ち上げた redis を使って簡単なログイン機能を実装する手順
Node.js の Express と docker で立ち上げた redis を使って簡単なログイン機能を実装する手順をメモしました。
構成
Node.js と Express で立ち上げた web アプリから docker で立ち上げた redis へセッション情報を保存する構成で作成します。
redis(レディス)
redis とは?
Redis(リモートディクショナリサーバー)とは、オープンソースで提供されている高速なメモリ内 Key-Value データストアです。 データベース、キャッシュ、メッセージブローカー、およびキューなどを用途として利用します。
公式サイト
環境
- Mac OS Big SUR 11.3.1
- yarn 1.22.10
- Node 14.15.3
- express 4.17.1
- express-session 1.17.2
- redis 3.1.2
ファイル操作で利用する Unix コマンドについて
基本的なディレクトリ作成やファイル操作は Unix コマンドを利用します。
Unix コマンドについて詳しくはこちらの記事を参考にしてください。
事前準備
Docker 環境が必要
事前準備として Docker が利用できる環境で実施します。Docker のインストール手順についてはこちらを参照ください。
Node.js 環境が必要
事前準備として Node.js が利用できる環境で実施します。
Node.js の環境の構築について詳しくはこちらの記事を参考にしてください。
yarn コマンドのインストール
事前準備として Yarn が利用できる環境で実施します。
Yarn コマンドのインストールについて詳しくはこちらの記事を参考にしてください。
TypeScript 環境で実施
事前準備として TypeScript が利用できる環境で実施します。
TypeScript の実行環境の構築について詳しくはこちらの記事を参考にしてください。
プロジェクトの作成
プロジェクトディレクトリを作成
~/login-sample
というプロジェクトディレクトリを作成します。
terminal$ mkdir ~/login-sample
プロジェクトディレクトリへ移動
作成した~/login-sample ディレクトリへ移動します。
terminal$ mkdir ~/login-sample
yarn を初期化をして package.json を作成
yarn でプロジェクトの初期化を行います。
npm で実施する方は必要に応じて変更してください。
terminal$ yarn init -y
yarn init v1.22.10
warning The yes flag has been set. This will automatically answer yes to all questions, which may have security implications.
success Saved package.json
✨ Done in 0.08s.
必要なパッケージのインストール
必要なパッケージ
experss と TypeScript のパッケージをインストールします。
- express
- express-session
- cookie-parser
- redis
- connect-redis
- @types/express
- @types/express-session
- @types/cookie-parser
- @types/redis
- @types/connect-redis
- typescript
- @types/node
- ts-node
express
Express フレームワークのモジュールです。
express-session
Express でセッションを扱えるようにするためのミドルウェアです。
cookie-parser
cookie を読み取るためのミドルウェアです。Express のミドルウェアへ設定して利用します。
redis
Redis のモジュールです。
connect-redis
express-session のセッション保存先に redis を扱えるようにするモジュールです。
パッケージのインストール
yarn add
コマンドで必要パッケージをインストールします。
terminal$ yarn add express express-session cookie-parser redis connect-redis
開発に関連するパッケージのため -D
オプションを付与しています。
sql$ yarn add -D @types/express-session @types/cookie-parser @types/redis @types/connect-redis @types/express typescript @types/node
インストールしたパッケージを確認
package.json
を開きインストールされたパッケージを確認します。
perl "devDependencies": {
"@types/connect-redis": "^0.0.16",
"@types/cookie-parser": "^1.4.2",
"@types/express": "^4.17.12",
"@types/express-session": "^1.17.3",
"@types/node": "^15.12.5",
"@types/redis": "^2.8.30",
"ts-node": "^10.0.0",
"typescript": "^4.3.4"
},
"dependencies": {
"connect-redis": "^6.0.0",
"cookie-parser": "^1.4.5",
"express": "^4.17.1",
"express-session": "^1.17.2",
"redis": "^3.1.2"
}
設定ファイルを作成
tsconfig.json を作成
プロジェクトルートへ tsconfig.json を作成します。
terminal$ vi tsconfig.json
tsconfig.json の設定例
tsconfig.json{
"compilerOptions": {
"target": "es2020",
"module": "commonjs",
"lib": [
"es2020"
],
"sourceMap": true,
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"moduleResolution": "node",
"baseUrl": "src",
"esModuleInterop": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": [
"src/**/*"
],
"exclude": [
"dist",
"node_modules"
],
"compileOnSave": false
}
ts-config のオプションはこちらの記事を参考にしてください
Redis の立ち上げ
アプリケーションから接続する必要があるため先に Redis を立ち上げます。
docker-compose.yml を利用して docker でサクッと立ち上げます。
docker-compose.yml を作成
プロジェクトのルートディレクトリへ docker-compose.yml を作成します。
terminal$ vi docker-compose.yml
redis の設定記述
redis の設定を記述します。
docker-compose.ymlversion: '3.5'
services:
redis:
image: 'redis'
ports:
- '6379:6379'
volumes:
- './data:/data'
データ永続化のための data ディレクトリ作成
プロジェクトルートへデータ永続化のための data ディレクトリを作成します。
terminal$ mkdir data
docker を立ち上げ
docker-compose up
コマンドで redis を立ち上げます。
terminaldocker-compose up -d
// 中略
Status: Downloaded newer image for redis:latest
Creating login-sample_redis_1 ... done
docker の起動を確認
docker ps
コマンドで redis の起動を確認します。
bash$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
11387a81aa9b redis "docker-entrypoint.s…" About a minute ago Up 56 seconds 0.0.0.0:6379->6379/tcp, :::6379->6379/tcp login-sample_redis_1
以上で redis の立ち上げは完了です。
アプリケーションの構築
ソースディレクトリの作成
プロジェクトルートへsrc
ディレクトリを作成します。
terminal$ mkdir src
アプリケーションのファイルを作成
作成したソースディレクトリへ index.ts を追加します。
terminal$ vi src/index.ts
アプリケーションの設定を追記
利用するモジュールをインポート
import 文で利用するモジュールをインポートします。
src/index.tsimport express from 'express';
import cookieParser from 'cookie-parser';
import session from 'express-session';
import redis from 'redis';
import connectRedis from 'connect-redis';
各種初期化を実施
Express の初期化
import した express を呼び出して express を初期化します。
src/index.tsconst app = express();
express-session の初期化
redis を使用するための設定です。 connect-redis へ express-session を渡します。
src/index.tsconst RedisStore = connectRedis(session);
Redis の初期化
import した express を呼び出して express を初期化します。
src/index.tsconst redisClient = redis.createClient({
host: 'localhost',
port: 6379,
prefix: 'sid:',
});
redisClient.unref();
redisClient.on('error', console.log);
connect-redisのversion4で一部書き方が変わっています。 connect-redis/migration-to-v4.md at master · tj/connect-redis
ミドルウェアの設定
cookie-parser
express のミドルウェアへ cookie-parser を設定します。
src/index.tsapp.use(cookieParser())
body-parser
express のミドルウェアへ body-parser を設定してpostデータを受け取れるようにします。
body-parserはexpressに内包されるように変更になりました。
src/index.tsapp.use(express.urlencoded());
session の設定
express のミドルウェアへ settion の設定を渡します。
src/index.tsapp.use(
session({
secret: 'secret_key',
resave: true,
saveUninitialized: true,
store: new RedisStore({ client: redisClient }),
cookie: {
httpOnly: true,
secure: false,
maxAge: 1000 * 60 * 30,
},
})
);
secret
セッション ID Cookie に署名するために使用される文字列です。
任意の値を指定します。
resave
要求中にセッションが変更されなかった場合でも、セッションをセッションストアに強制的に保存するかどうかの設定です。
デフォルトを使用することは推奨されなくなったため明示的に指定しています。
saveUninitialized
「初期化されていない」セッションを強制的にセッション・ストアに保存するかどうかの設定です。
デフォルトを使用することは推奨されなくなったため明示的に指定しています。
store
セッションストアインスタンスになります。
ここで redis を指定しています。
cookie
Cookie の設定用のオブジェクトになります。
オプションについて詳細はこちらをご確認ください。
expressjs/session: Simple session middleware for Express
型の拡張
express-sessionでuser_idを利用するため型ファイルを拡張します。
型の拡張用のディレクトリ追加
terminal$ mkdir -p src/@types
@types.express-session.d.tsを作成
@types.express-session.d.tsを作成します。
terminal$ vi src/@types/express-session.d.ts
型の定義を追加
src/@types/express-session.d.tsimport 'express-session';
declare module 'express-session' {
interface SessionData {
user_id: string;
}
}
ログインページの作成
ログインページを作成します。
ログインページの仕様
クライアント
- ユーザー ID を入力するための入力ボックスを作成
- 送信ボタンを作成
- 送信ボタンをクリックしたら post でユーザー ID を送信する
サーバー
- アクセス URL は
/login
- GET ならページを表示
- POST ならデータを確認してユーザー ID が送られてきたらユーザー ID をセッションへ保存し'/'へリダイレクト
クライアントの処理
ソースディレクトリ内へhtmlファイルを作成します。
htmlを格納するディレクトリ
htmlを格納するディレクトリを作成します。
terminal$ mkdir src/html
login.htmlを作成
login.htmlを作成します。
css$ vi src/html/login.html
login.html
入力されたuser_id
をポストするだけの簡易的なformを作成しています。
src/html/login.html<form action="/login" method="post">
<p>ユーザーID</p>
<input type="text" name="user_id" value="" />
<input type="submit" value="送信" />
</form>
サーバーの処理
GET時の処理
/login
へのgetのリクエストでhtmlを表示します。
src/index.tsapp.get(
'/login',
(req: express.Request, res: express.Response): void => {
// login.htmlファイルを表示
res.sendFile(`${__dirname}/html/login.html`);
}
);
POST時の処理
/login
へのPOSTでuser_idがあったらsessionへ保存してリダイレクトさせます。
src/index.tsapp.post(
'/login',
(req: express.Request, res: express.Response): void => {
const { user_id } = req.body;
if (user_id) {
req.session.user_id = user_id;
res.redirect('/');
}
}
);
トップページの作成
トップページを作成します。
トップページの仕様
クライアント
- ユーザー ID を表示
- ログアウトページのリンクを表示
サーバー
- セッションのユーザー ID が存在したらページを表示
- セッションのユーザー ID が存在しなかったらログインページへリダイレクト
index.tsへトップページの処理追加
/
のGETでアクセスがあったらsessionのuser_id
を確認。
なかったら/login
へリダイレクトし
あったらuser_id
とlinkタグを出力
src/index.tsapp.get(
'/',
(req: express.Request, res: express.Response): void => {
const { user_id } = req.session;
if (!user_id) {
res.redirect('/login');
}
console.log(user_id);
res.send(
`ようこそ${user_id}さん<br><a href="/logout">ログアウト</a>`
);
}
);
ログアウト処理の作成
ログアウトページを作成します。
ログアウト処理の仕様
サーバー
- セッションを削除してログインページへリダイレクト
index.tsへログアウト処理追加
user_id
をdeleteして/login
へリダイレクトします。
iniapp.get(
'/logout',
(req: express.Request, res: express.Response): void => {
delete req.session.user_id;
res.redirect('/login');
}
);
アプリケーションを起動
アプリケーションを起動させていきます。
npm scripts へ起動コマンドの追加
実行するコマンドを追記します。
package.json
package.json "scripts": {
"start": "node dist/index.js",
"build": "tsc",
"dev": "ts-node src/index.ts"
},
devでアプリサーバーを起動
yarn dev
コマンドを実行します。
terminal$ yarn dev
yarn run v1.22.10
$ ts-node src/index.ts
listening on *:8080
8080で待ち受ける形でアプリケーションが起動しました。
アプリの動作テスト
起動させたアプリケーションをブラウザで確認してみます。
入力して送信
ログアウト処理を実行
入力した文字列が表示されているか確認します。
そしてログアウトをクリックしてログインページへ戻るか確認します。
ログイン・ログアウト処理を確認することが出来ました。
Redisのログ確認
起動しているコンテナIDを確認
docker ps
コマンドで redis のコンテナIDを確認します。
bash$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
11387a81aa9b redis "docker-entrypoint.s…" About a minute ago Up 56 seconds 0.0.0.0:6379->6379/tcp, :::6379->6379/tcp login-sample_redis_1
redisへログイン
docker exec
コマンドでログインします。
ruby$ docker exec -it 11387a81aa9b bash
root@11387a81aa9b:/data#
キーを確認
保存されているキーを確認します。
ruby127.0.0.1:6379> keys *
1) "sid:sess:nelbdFcxCEp1juSAFvkEmCE18Ol4-aEM"
getで保存されている内容を確認
ログイン時
ログイン時はuser_idが入っていることが確認できました。
swift127.0.0.1:6379> get sid:sess:nelbdFcxCEp1juSAFvkEmCE18Ol4-aEM
"{\"cookie\":{\"originalMaxAge\":1799999,\"expires\":\"2021-06-29T10:07:39.754Z\",\"secure\":false,\"httpOnly\":true,\"path\":\"/\"},\"user_id\":\"xxx\"}"
ログアウト時
ログアウトするとuser_idが削除されていることが確認できました。
swift127.0.0.1:6379> get sid:sess:nelbdFcxCEp1juSAFvkEmCE18Ol4-aEM
"{\"cookie\":{\"originalMaxAge\":1799999,\"expires\":\"2021-06-29T10:25:35.933Z\",\"secure\":false,\"httpOnly\":true,\"path\":\"/\"}}"
以上でログイン・ログアウトの動作確認は完了です。
記事Article
もっと見る- article
Dockerの利用していないゴミを掃除しディスクスペースを解放するいくつかのやり方を紹介
- article
Next.js のバンドルサイズを可視化する@next/bundle-analyzer の紹介
- article
VSCodeでTypescriptファイルのimport補完で相対パスではなくエイリアスするための設定
- article
UUIDより短いユニークなIDを生成できるnpmライブラリnanoidの使い方
- article
【解決方法】TypeScript発生したTS2564 エラーの対処
- article
express で IP を取得する際などに利用する req.connection 非推奨(deprecated)の対処