はじめに
ベクトルタイルサーバーを磨き上げる一環で、開発環境で使っていた 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) を参考につけた。(Azure AD は自分のマイクロソフトアカウントで APPの登録をした。)
ここまでやったレポジトリが ubukawa/server-test-01 で、このことは前の記事 に書いた(まとまっていなくてすみません)。
ここまでの課題と方針
ここまででは、express-session を使っていて、ユーザーの保存がインメモリセッションなのでProduction環境では適切なものに置き換える必要がある。msalClientもlocalsで管理されていて、次にやらないといけないのだが、まずはexpress-session の sessionをやる。mysqlの方がシンプルでよさそうなので express-mysql-session がよいだろうと判断した。
Step2: mysqlのインストール
ベクトルタイルサーバーから、ローカルホストとして立っているユーザー管理データベースにアクセスさせるため、サーバーにmysqlをインストールした。自分のテスト環境はCentOSなので、mysqlのインストールについては以下が非常に参考になり、その手順を守ってインストールした。(ありがとうございます。)
CentOS7にMySQLをインストールして初期設定するまで
そして、専用のユーザーを作り、データベースの作成、レコード追加・削除等の必要そうな権限を与えた。ベクトルタイルサーバーと同じ環境にmysqlを入れてローカルホストへの接続という形でmysqlデータベースにアクセスさせてみることにする。(ただし、これだけでは不十分。step4を参照。)
Step3: express-mysql-session の追加
もともとの app.js をよく見ると、比較的単純に express-session を express-mysql-session に置き換えられるのではないかと思った。まず、express-mysql-sessionのモジュールを追加。
const session = require('express-session');
const MySQLStore = require('express-mysql-session')(session); //追加分
Express-session でsessionを使っていたところに、express-mysql-session のセッションストアを指定する。(パスワードとデータベース名は.envに入れて読まるようにしました。)
//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で以下のコマンドを実行した。
ALTER USER '(決めたユーザー)'@'localhost' IDENTIFIED WITH mysql_native_password BY '(パスワード)';
flush privileges;
そのあと、mysqlのデータベースに値が入るので、sessionストアとして、一応は動いている模様。
Step5: まだ動作しない。
データベースはvtUserとしておいて作っておきました。中身を見るとsessionsというテーブルがあるので、session情報が書き込まれているようです。
一応、セッションの中にはuseIdが入っているものもあるようです。auth.jsのcallbackにきちんと返ってくると、homeidが req.session.userId として記録される。(このリスト、翌日見たら消えていたので、きちんとexpireしたのは消えるのかなと思います。)
ただ、インデックスページが返ってこないので、今確認中です。
sessionの問題というより、コールバックとそのあとのホームページ描画関係のものをいじってしまったのかもしれません。
(作業を継続しているので、出来たら追記します。)
→
Azure AD認証の時のscope('user.read,calendars.readwrite,mailboxsettings.read'等)の関係の問題のようです。
内部のAzure ADを使ってテストしたらうまくいきました。
まとめ
express-sessionのsessionstoreをmysqlのデータベースにすることができました。