nodejsサーバーでexpress-mysql-sessionをつかう

## はじめに
ベクトルタイルサーバーを磨き上げる一環で、開発環境で使っていた in-memory session store を mysql のデータベースに置き換えようとしている。

## 環境
* Cent OS Linux release 7.8.2003
* nodejs ver. 16.13.1
* npm ver. 8.1.2
* mysql Ver. 8.0.27 for Linux on x86_64 (MySQL Community Server - GPL)


## 手順

### Step1: Azure AD認証つきのnodejsサーバーの準備
nodejs/expressサーバーを作る。msalでのAzure AD認証は Microsoftのチュートリアル （[Build Node.js Express apps with Microsoft Graph](https://docs.microsoft.com/en-us/graph/tutorials/node?WT.mc_id=Portal-Microsoft_AAD_RegisteredApps)） を参考につけた。（Azure AD は自分のマイクロソフトアカウントで APPの登録をした。）

ここまでやったレポジトリが [ubukawa/server-test-01](https://github.com/ubukawa/server-test-01) で、このことは[前の記事](https://qiita.com/T-ubu/items/f7147def371b49cb232c) に書いた（まとまっていなくてすみません）。

#### ここまでの課題と方針
ここまででは、[express-session](https://www.npmjs.com/package/express-session) を使っていて、ユーザーの保存がインメモリセッションなのでProduction環境では適切なものに置き換える必要がある。msalClientもlocalsで管理されていて、次にやらないといけないのだが、まずはexpress-session の sessionをやる。mysqlの方がシンプルでよさそうなので [express-mysql-session](https://www.npmjs.com/package/express-mysql-session) がよいだろうと判断した。

### Step2: mysqlのインストール
ベクトルタイルサーバーから、ローカルホストとして立っているユーザー管理データベースにアクセスさせるため、サーバーにmysqlをインストールした。自分のテスト環境はCentOSなので、mysqlのインストールについては以下が非常に参考になり、その手順を守ってインストールした。（ありがとうございます。）

[CentOS7にMySQLをインストールして初期設定するまで](https://qiita.com/nooboolean/items/7efc5c35b2e95637d8c1)


そして、専用のユーザーを作り、データベースの作成、レコード追加・削除等の必要そうな権限を与えた。ベクトルタイルサーバーと同じ環境にmysqlを入れてローカルホストへの接続という形でmysqlデータベースにアクセスさせてみることにする。（ただし、これだけでは不十分。step4を参照。）

### Step3: express-mysql-session　の追加
もともとの app.js をよく見ると、比較的単純に express-session を express-mysql-session に置き換えられるのではないかと思った。まず、express-mysql-sessionのモジュールを追加。

```js:app.jsの冒頭（一部）
const session = require('express-session');
const MySQLStore = require('express-mysql-session')(session); //追加分
```
Express-session でsessionを使っていたところに、express-mysql-session のセッションストアを指定する。（パスワードとデータベース名は.envに入れて読まるようにしました。）

```js:app.jsの一部
//Session witl mysql (from here)////////////////////////
const mysqlOptions ={
  host: 'localhost',
  port: 3306,
  user: 'hoge',
  password: process.env.MYSQL_PASSWORD, 
  database: process.env.MYSQL_DATABASE
};

const sessionStore = new MySQLStore(mysqlOptions);
const sess = {
  secret: process.env.hoge,
  cookie: {maxAge: 60000000},　
  store: new MySQLStore(mysqlOptions),
  resave: false,
  saveUninitialized: false
}

sess.cookie.secure = true; //for production
app.use(session(sess))
//Session witl mysql (until here)////////////////////////

/*
//もともとのセッション
app.use(session({
  secret: process.env.hoge,
  resave: false,
  saveUninitialized: false,
  unset: 'destroy'
}));
*/
```

という感じにして動かしてみた。（ローカルホストではなく、外部の練習サーバーで実験。）
セッションのパラメータについては、最初、cookieのmaxAgeの単位を秒だと勘違いしていたので、えらく早くセッションが切れてしまったのですが、ミリ秒だと気づいてなおしました。resaveとsaveUninitializedは適宜の設定にします。


### Step4: エラーの処理
ところが、サーバー側で、
ER_NOT_SUPPORTED_AUTH_MODE: Client does not support authentication protocol requested by server; consider upgrading MySQL client 
というエラーがでた。調べてみると、mysqlにアクセスできていないようなので、ベクトルタイルサーバーからmysqlに接続するために、mysqlで以下のコマンドを実行した。

```sql
ALTER USER '（決めたユーザー）'@'localhost' IDENTIFIED WITH mysql_native_password BY '（パスワード）';
flush privileges;
```

そのあと、mysqlのデータベースに値が入るので、sessionストアとして、一応は動いている模様。


### Step5: まだ動作しない。
データベースはvtUserとしておいて作っておきました。中身を見るとsessionsというテーブルがあるので、session情報が書き込まれているようです。
![2021-12-24-mysql-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/480b3497-c758-bcc2-038b-94067c7c16d9.png)

一応、セッションの中にはuseIdが入っているものもあるようです。auth.jsのcallbackにきちんと返ってくると、homeidが req.session.userId として記録される。（このリスト、翌日見たら消えていたので、きちんとexpireしたのは消えるのかなと思います。）

![2021-12-24-mysql-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/5aad0a76-8735-989b-ae72-1025a6a0390d.png)

ただ、インデックスページが返ってこないので、今確認中です。
sessionの問題というより、コールバックとそのあとのホームページ描画関係のものをいじってしまったのかもしれません。
（作業を継続しているので、出来たら追記します。）

→ 
Azure AD認証の時のscope（'user.read,calendars.readwrite,mailboxsettings.read'等）の関係の問題のようです。
内部のAzure ADを使ってテストしたらうまくいきました。

## まとめ
express-sessionのsessionstoreをmysqlのデータベースにすることができました。


## 参考にしたページなど
* [Build Node.js Express apps with Microsoft Graph](https://docs.microsoft.com/en-us/graph/tutorials/node?WT.mc_id=Portal-Microsoft_AAD_RegisteredApps)
* [CentOS7にMySQLをインストールして初期設定するまで](https://qiita.com/nooboolean/items/7efc5c35b2e95637d8c1)
* [[Node.js][Express]セッションを使う](https://tech.chakapoko.com/nodejs/express/session.html)
* [MySQL 8.0 - Client does not support authentication protocol requested by server; consider upgrading MySQL client](https://stackoverflow.com/questions/50093144/mysql-8-0-client-does-not-support-authentication-protocol-requested-by-server)