ユーザー機能の実装
postgressにユーザー情報を保存するテーブルを作成
CREATE TABLE users (
user_id SERIAL NOT NULL,
user_name VARCHAR(255) NOT NULL,
user_email VARCHAR(255) NOT NULL,
user_password VARCHAR(255) NOT NULL,
created_at TIMESTAMP NOT NULL,
PRIMARY KEY (user_id)
);
誰がchannelを投稿したのか見られるように、channel
とmessage
のテーブルにuser_id
のカラムを追加します。
/*channelテーブル*/
ALTER TABLE channel ADD COLUMN user_id INTEGER;
/*messagesテーブル*/
ALTER TABLE messages ADD COLUMN user_id INTEGER;
ユーザー登録機能
app.js
にコードを追加します。
// 中略
const message = require('./routes/message');
const signup = require('./routes/signup'); // 追加
const app = express();
// 中略
app.use('/message', message);
app.use('/signup', signup); //追加
routes/signup.js
を作成します。
const express = require('express');
const router = express.Router();
const dayjs = require('dayjs');
const pool = require('../dbConnection');
router.get('/', (req, res, next) => {
res.render('signup', {
title: '新規会員登録'
});
});
router.post('/', async (req, res, next) => {
try {
const userName = req.body.user_name;
const email = req.body.email;
const password = req.body.password;
const createdAt = dayjs().format('YYYY-MM-DD HH:mm');
const signupQuery =
'INSERT INTO users (user_name, user_email, user_password, created_at) VALUES ($1, $2, $3, $4)';
// 既に登録されているメールアドレスかどうかを確認
const emailExistsQuery = 'SELECT * FROM users WHERE user_email = $1 LIMIT 1';
const emailExists = await pool.query(emailExistsQuery, [email]);
if (emailExists.rows.length) {
res.render('signup', {
title: '新規会員登録',
emailExists: '既に登録されているメールアドレスです'
});
} else {
// ユーザーの新規登録
await pool.query(signupQuery, [userName, email, password, createdAt]);
res.redirect('/signup');
}
} catch (error) {
console.error(error);
res.status(500).send('内部サーバーエラー');
}
});
module.exports = router;
views/signup.ejs
を作成します。
<!DOCTYPE html>
<html lang="ja">
<head>
<title><%= title %></title>
<link rel='stylesheet' href='/stylesheets/style.css' />
</head>
<body>
<div class="top_link">
<a href="/" class="btn">← トップへもどる</a>
</div>
<p class="main-title"><%= title %></p>
<% if (typeof emailExists !== 'undefined') { %>
<p class="error"><%= emailExists %></p>
<% } %>
<form action="/signup" method="post" class="form">
<div class="userName">
<span class="label">userName</span>
<input type="text" name="user_name" class="input" required>
</div>
<div class="email">
<span class="label">Email</span>
<input type="email" name="email" class="input" required>
</div>
<div class="password">
<span class="label">password</span>
<input type="password" name="password" class="input" required>
</div>
<div class="button-area">
<button type="submit" class="submit">新規会員登録</button>
</div>
</form>
</body>
</html>
/signup
にアクセスしてユーザー登録をしてみてください
エラーが表示されていればOKです
passwordをhush値にしてデータベースに保存する
データベースに入力したままのpasswordを保存するのは良く無いのでモジュールを使ってpasswordをhush値にしてデータベースに登録します
npm install --save bcrypt
routes/signup.js
にコード追加
const express = require('express');
const router = express.Router();
const dayjs = require('dayjs');
const bcrypt = require('bcrypt'); //追加
const pool = require('../dbConnection');
router.get('/', (req, res, next) => {
res.render('signup', {
title: '新規会員登録'
});
});
router.post('/', async (req, res, next) => {
try {
const userName = req.body.user_name;
const email = req.body.email;
const password = req.body.password;
const createdAt = dayjs().format('YYYY-MM-DD HH:mm:ss');
const signupQuery = 'INSERT INTO users (user_name, user_email, user_password, created_at) VALUES ($1, $2, $3, $4)';
// 既に登録されているメールアドレスかどうかを確認
const emailExistsQuery = 'SELECT * FROM users WHERE user_email = $1 LIMIT 1';
const emailExists = await pool.query(emailExistsQuery, [email]);
if (emailExists.rows.length) {
res.render('signup', {
title: '新規会員登録',
emailExists: '既に登録されているメールアドレスです'
});
} else {
// パスワードのハッシュ化
const hashedPassword = await bcrypt.hash(password, 10);
// ユーザーの新規登録
//password → hashedPasswordに変更
await pool.query(signupQuery, [userName, email, hashedPassword, createdAt]);
res.redirect('/signup');
}
} catch (error) {
console.error(error);
res.status(500).send('内部サーバーエラー');
}
});
module.exports = router;
こうなってればOK
ログイン機能の実装
ログイン情報を保持する為に必要なモジュールをインストールします
npm install --save express-session
app.js
を書き換えます
// 中略
const logger = require('morgan');
const session = require('express-session'); // 追加
const indexRouter = require('./routes/index');
const message = require('./routes/message');
const signup = require('./routes/signup');
const login = require('./routes/login'); // 追加
// 中略
app.use(express.static(path.join(__dirname, 'public')));
// 追加 session
app.use(session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: true
}));
app.use('/', indexRouter);
app.use('/message', message);
app.use('/signup', signup);
app.use('/login', login); // 追加
// 中略
routes/login.js
を作成します。
const express = require('express');
const router = express.Router();
const bcrypt = require('bcrypt');
const pool = require('../dbConnection');
router.get('/', function (req, res, next) {
if (req.session.user_id) {
res.redirect('/');
} else {
res.render('login', {
title: 'ログイン'
});
}
});
router.post('/', async function (req, res, next) {
try {
const email = req.body.email;
const password = req.body.password;
const query = 'SELECT user_id, user_password FROM users WHERE user_email = $1 LIMIT 1';
const result = await pool.query(query, [email]);
if (result.rows.length > 0) {
const user = result.rows[0];
const userId = user.user_id;
// パスワードの比較
const isPasswordValid = await bcrypt.compare(password, user.user_password);
if (isPasswordValid) {
req.session.user_id = userId;
res.redirect('/');
return; // ログイン成功時に関数を終了
}
}
// 行が見つからないか、パスワードが無効な場合のエラーメッセージ
res.render('login', {
title: 'ログイン',
noUser: 'メールアドレスとパスワードが一致するユーザーはいません'
});
} catch (error) {
console.error(error);
res.status(500).send('内部サーバーエラー');
}
});
module.exports = router;
views/login.ejs
を作成します。
<!DOCTYPE html>
<html lang="ja">
<head>
<title><%= title %></title>
<link rel='stylesheet' href='/stylesheets/style.css' />
</head>
<body>
<div class="top_link">
<a href="/" class="btn">← トップへもどる</a>
</div>
<p class="main-title"><%= title %></p>
<% if (typeof noUser !== 'undefined') { %>
<p class="error"><%= noUser %></p>
<% } %>
<form action="/login" method="post" class="form">
<div>
<span class="label">Eメール</span>
<input type="email" name="email" class="input" required>
</div>
<div>
<span class="label">パスワード</span>
<input type="password" name="password" class="input" required>
<div>
<div class="button-area">
<button type="submit" class="submit">ログイン</button>
</div>
</form>
</body>
</html>
ユーザー登録画面で登録したユーザーでログインしてみてください。
エラーが出ずにログインできたらOKです
ログインしているユーザーを表示させる
app.js
を書き換える
// 中略
const login = require('./routes/login');
const setUser = require('./routes/setUser'); // 追加
const app = express();
// 中略
app.use('/', setUser, indexRouter); // 変更
app.use('/users', usersRouter);
app.use('/message', setUser, message); // 変更
app.use('/signup', signup);
app.use('/login', login);
// 中略
routes/setUser.js
を作成します
const pool = require('../dbConnection');
module.exports = async (req, res, next) => {
const userId = req.session.user_id;
if (userId) {
try {
const query = 'SELECT user_id, user_name FROM users WHERE user_id = $1';
const result = await pool.query(query, [userId]);
if (result.rows.length) {
res.locals.user = result.rows[0];
}
} catch (error) {
console.error(error);
}
}
next();
};
views/index.ejs
を書き換えます
<% if (typeof user !=='undefined' ) { %>
<span class="login-user">
<%= user.user_name %>さんとしてログインしています
</span>
<% } %>
views/message.ejs
を書き換えます
<% if (typeof user !=='undefined' ) { %>
<span class="login-user">
<%= user.user_name %>さんとしてログインしています
</span>
<% } %>
ログアウト機能を実装
app.jsを変更します
// 中略
var login = require('./routes/login');
var logout = require('./routes/logout'); // 追加
var setUser = require('./routes/setUser');
const app = express();
// 中略
app.use('/login', login);
app.use('/logout', logout); // 追加
routes/logout.js
を作成します
const express = require('express');
const router = express.Router();
router.get('/', (req, res, next) => {
req.session.destroy();
res.redirect('/login');
});
module.exports = router;
ログアウトされていればOKです
ユーザー登録ボタン、ログインボタン、ログアウトボタンを作成する
自走課題です、難しければDiscordで質問してください。
条件
・ ログインしていない状態の時は、ユーザー登録ボタン
とログインボタン
の表示
・ ログインしている状態の時は、ユーザー登録ボタン
とログアウトボタン
の表示