前提
環境はこの人です。
Express, express-session, Sequelize が入っている前提で進めます。
https://github.com/mayarin/NodejsMySQLDocker
作業内容
以下のテーブルを作りました。
CREATE TABLE `users` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL, `mailaddress` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL, `password` text COLLATE utf8mb4_bin, `active` tinyint(1) DEFAULT NULL, `createdAt` datetime NOT NULL, `updatedAt` datetime NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin
アカウント登録時には
・既存メルアド確認
・アカウント作成後自動ログイン
とします。
既存メルアド確認には、SequelizeのfindAndCountAllを利用します。
const { count, rows } = await db.Users.findAndCountAll({ where: { mailaddress: req.body.mailaddress }, offset: 0, limit: 1 }); if(count == 0){ // 行がない場合のみアカウント登録処理 } else { // アカウントが重複している旨エラーを返す }
アカウント登録の実作業は、Sequelizeのcreateを利用します。
let hashed_password = bcrypt.hashSync(req.body.password, 10); // パスワードを平文で持たず暗号化します const newUser = await db.Users.create({ name: req.body.name, mailaddress: req.body.mailaddress, password : hashed_password, active: true }); if (newUser){ req.session.user = {id: newUser.id}; signup_failed_reason = ''; } else { signup_failed_reason = 'アカウント登録に失敗しました。'; }
パスワードの暗号化にはbcryptを利用しました。
https://www.npmjs.com/package/bcrypt
https://qiita.com/tatsumi44/items/83ac5c18f213e22ed322
パスワード照合でハマりました
一方ログイン時にパスワードを照合するところでハマりました。
router.post('/login', async function(req, res) { login_mailaddress = req.body.mailaddress; let hashed_password = bcrypt.hashSync(req.body.password, 10); const { count, rows } = await db.Users.findAndCountAll({ where: { mailaddress: req.body.mailaddress, password: hashed_password, }, offset: 0, limit: 1 });
いつもはCI4では以下の様に書いていて(多分めちゃくちゃ自己流)。
$password_query = sprintf("select HEX(AES_ENCRYPT('%s', '%s')) as enc_password", $this->request->getVar('update_password'), LOGIN_ENCRYPT_KEY); $enc_password = $this->db->query($password_query)->getRowArray()['enc_password']; // こいつを作ってアカウント検索時のwhere句に入れる
これと同じノリで照合しようと思ったんですが、生成するたびに違う暗号文が吐き出されるんです。
これbcryptでは考え方がそもそも誤っていて、compareSyncで照合するんです。
そうなると、メルアドの有無確認→パスワードの照合という流れになります。
完成品はこうなりました。
router.post('/login', async function(req, res) { login_mailaddress = req.body.mailaddress; const { count, rows } = await db.Users.findAndCountAll({ raw: true, where: { mailaddress: req.body.mailaddress, }, offset: 0, limit: 1 }); if(count == 0){ login_failed_reason = 'アカウントがありません。'; res.redirect('/'); } else { var row = rows[0]; if (bcrypt.compareSync(req.body.password, row.password) ) { req.session.user = {id: row.id}; } else { login_failed_reason = 'パスワードが誤っています。'; } res.redirect('/'); } });
参考サイト
https://qiita.com/tatsumi44/items/83ac5c18f213e22ed322
なおこの段階のgithubはこちらになります。
https://github.com/mayarin/NodejsMySQLDocker/releases/tag/20201102