- vừa được xem lúc

Blog#221: 🔐Node.js Expressで安全なパスワードリセット機能を実装する

0 0 23

Người đăng: NGUYỄN ANH TUẤN

Theo Viblo Asia

221

こんにちは、私はトゥアンと申します。東京からフルスタックWeb開発者です。 将来の有用で面白い記事を見逃さないように、私のブログをフォローしてください。😊

1. はじめに

この記事では、Node.js Expressアプリケーションで安全なパスワードリセット機能を実装する方法について説明します。パスワードリセットは、セキュリティと良好なユーザーエクスペリエンスを確保するための重要な機能です。これを実現するために、環境の設定からリセットメールの送信、最終的にユーザーのパスワードの更新までのプロセスを段階的に説明します。

2. プロジェクトの設定

2.1 プロジェクトの初期化

まず、プロジェクト用の新しいフォルダを作成し、コマンドラインでそのフォルダに移動します。次に、以下のコマンドを実行して、package.jsonファイルでプロジェクトを初期化します。

npm init -y

2.2 依存関係のインストール

次に、以下のコマンドを実行して、このプロジェクトに必要な依存関係をインストールします。

npm install express mongoose bcryptjs jsonwebtoken nodemailer dotenv

これらの依存関係には、以下が含まれます。

  • express:コアとなるExpressフレームワーク
  • mongoose:Node.js用のMongoDBオブジェクトモデリングライブラリ
  • bcryptjs:パスワードのハッシュ化と比較のためのライブラリ
  • jsonwebtoken:JSON Webトークンを生成・検証するためのライブラリ
  • nodemailer:メールを送信するためのモジュール
  • dotenv:.envファイルから環境変数を読み込むためのモジュール

3. 環境の設定

3.1 .envファイルの作成

プロジェクトのルートに.envファイルを作成し、機密データや環境固有の設定を保存します。ファイルに以下の行を追加します。

MONGODB_URI=mongodb://localhost:27017/password-reset
EMAIL_SERVICE=あなたのメールサービス
EMAIL_USER=あなたのメールアドレス
EMAIL_PASS=あなたのメールパスワード
JWT_SECRET=あなたのJWT秘密鍵

プレースホルダーを、メールサービスおよびアカウントの資格情報に適した値に置き換えてください。

3.2 環境変数の読み込み

メインアプリケーションファイル(例:app.js)で、dotenvモジュールをインポートし、.envファイルから環境変数を読み込むように設定します。

require('dotenv').config();

4. データベースの設定

4.1 MongoDBへの接続

Mongooseを使用して、MongoDBデータベースへの接続を確立します。app.jsファイルを以下のコードで更新します。

const express = require('express');
const mongoose = require('mongoose'); const app = express();
app.use(express.json()); mongoose.connect(process.env.MONGODB_URI, { useNewUrlParser: true, useUnifiedTopology: true }) .then(() => console.log('Connected to MongoDB')) .catch((err) => console.error('Failed to connect to MongoDB:', err)); const PORT = process.env.PORT || 3000;
app.listen(PORT, () => console.log(`Server is running on port ${PORT}`));

4.2 ユーザースキーマとモデルの定義

modelsという新しいフォルダを作成し、その中にUser.jsというファイルを作成します。次のコードでユーザースキーマとモデルを定義します。

const mongoose = require('mongoose');
const bcrypt = require('bcryptjs'); const userSchema = new mongoose.Schema({ email: { type: String, required: true, unique: true }, password: { type: String, required: true }, passwordResetToken: { type: String }, passwordResetExpires: { type: Date },
}); // データベースに保存する前にパスワードをハッシュ化する
userSchema.pre('save', async function (next) { if (!this.isModified('password')) return next(); const salt = await bcrypt.genSalt(10); this.password = await bcrypt.hash(this.password, salt); next();
}); // ユーザーのパスワードを検証するインスタンスメソッド
userSchema.methods.validatePassword = async function (password) { return await bcrypt.compare(password, this.password);
}; const User = mongoose.model('User', userSchema);
module.exports = User;

5. パスワードリセット機能の実装

5.1 ルートの設定

routesという新しいフォルダを作成し、その中にauth.jsというファイルを作成します。以下のルートを設定します。

  • /auth/forgot-password:パスワードリセットプロセスを開始するため
  • /auth/reset-password:実際のパスワードリセットを処理するため
const express = require('express');
const router = express.Router();
const { forgotPassword, resetPassword } = require('../controllers/authController'); router.post('/forgot-password', forgotPassword);
router.post('/reset-password', resetPassword); module.exports = router;

次に、app.jsファイルでauth.jsルータをインポートして使用します。

const authRoutes = require('./routes/auth'); app.use('/auth', authRoutes);

5.2 Authコントローラの作成

controllersという新しいフォルダを作成し、その中にauthController.jsというファイルを作成します。このファイルには、パスワードリセットプロセスを処理するためのコントローラ関数が含まれます。

const User = require('../models/User');
const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');
const nodemailer = require('nodemailer'); const transporter = nodemailer.createTransport({ service: process.env.EMAIL_SERVICE, auth: { user: process.env.EMAIL_USER, pass: process.env.EMAIL_PASS, },
}); async function forgotPassword(req, res) { // TODO: forgotPassword関数を実装する
} async function resetPassword(req, res) { // TODO: resetPassword関数を実装する
} module.exports = { forgotPassword, resetPassword,
};

5.3 forgotPassword関数の実装

authController.jsファイルで、パスワードリセット要求を処理するためのforgotPassword関数を実装します。

async function forgotPassword(req, res) { // メールでユーザーを見つける const user = await User.findOne({ email: req.body.email }); if (!user) { return res.status(404).json({ error: 'ユーザーが見つかりません' }); } // パスワードリセットトークンを生成し、有効期限を設定する const token = jwt.sign({ id: user._id }, process.env.JWT_SECRET, { expiresIn: '1h' }); user.passwordResetToken = token; user.passwordResetExpires = Date.now() + 3600000; // 1時間 await user.save(); // パスワードリセットメールを送信する const resetUrl = `http://${req.headers.host}/auth/reset-password?token=${token}`; const mailOptions = { from: process.env.EMAIL_USER, to: user.email, subject: 'パスワードリセットリクエスト', html: ` <p>パスワードリセットをリクエストしました。以下のリンクをクリックしてパスワードをリセットしてください。<\p> <a href="${resetUrl}">${resetUrl}<\a> <p>このリクエストを行っていない場合は、このメールを無視してください。<\p> `, }; try { await transporter.sendMail(mailOptions); res.json({ message: 'パスワードリセットメールが送信されました' }); } catch (err) { console.error('パスワードリセットメールの送信に失敗しました:', err); res.status(500).json({ error: 'パスワードリセットメールの送信に失敗しました' }); }
}

5.4 resetPassword関数の実装

authController.jsファイルで、パスワードリセットの確認とユーザーのパスワードの更新を処理するためのresetPassword関数を実装します。

async function resetPassword(req, res) { // パスワードリセットトークンを検証する const token = req.query.token; const decodedToken = jwt.verify(token, process.env.JWT_SECRET); // IDとトークンでユーザーを検索し、トークンがまだ有効かどうかを確認する const user = await User.findOne({ _id: decodedToken.id, passwordResetToken: token, passwordResetExpires: { $gt: Date.now() }, }); if (!user) { return res.status(401).json({ error: '無効または期限切れのパスワードリセットトークン' }); } // ユーザーのパスワードを更新し、リセットトークンとその有効期限を削除する user.password = req.body.password; user.passwordResetToken = undefined; user.passwordResetExpires = undefined; await user.save(); // 確認メールを送信する const mailOptions = { from: process.env.EMAIL_USER, to: user.email, subject: 'パスワードリセット確認', html: ` <p>パスワードが正常にリセットされました。このリクエストを行っていない場合は、すぐにお問い合わせください。</p> `, }; try { await transporter.sendMail(mailOptions); res.json({ message: 'パスワードリセットが成功しました' }); } catch (err) { console.error('パスワードリセット確認メールの送信に失敗しました:', err); res.status(500).json({ error: 'パスワードリセット確認メールの送信に失敗しました' }); }
}

6. 実装のテスト

パスワードリセット機能をテストするには、Postmanやcurlなどのツールを使用して、/auth/forgot-passwordおよび/auth/reset-passwordエンドポイントにリクエストを送信します。以下は、Postmanを使用してリクエストを送信する手順です。

  1. Postmanを開き、新しいリクエストを作成します。
  2. リクエストタイプをPOSTに設定し、http://localhost:3000/auth/forgot-passwordをURLに入力します。
  3. Bodyタブを選択し、rawを選択して、JSONを選択します。
  4. ボディに次のJSONオブジェクトを入力し、登録済みのユーザーのメールアドレスを指定します。
    { "email": "user@example.com"
    }
    
  5. Sendボタンをクリックしてリクエストを送信します。正常なレスポンスが返され、指定したメールアドレスにパスワードリセットメールが送信されます。
  6. メールに記載されているリセットリンクをコピーし、Postmanで新しいリクエストを作成します。
  7. リクエストタイプをPOSTに設定し、http://localhost:3000/auth/reset-password?token=コピーしたトークンをURLに入力します。
  8. 再びBodyタブを選択し、rawを選択して、JSONを選択します。
  9. ボディに次のJSONオブジェクトを入力し、新しいパスワードを指定します。
    { "password": "new-password"
    }
    
  10. Sendボタンをクリックしてリクエストを送信します。正常なレスポンスが返され、パスワードがリセットされます。

7. まとめ

この記事では、Node.js Expressアプリケーションで安全なパスワードリセット機能を実装する方法について説明しました。これにより、ユーザーはパスワードを忘れた場合でも、セキュアな方法でアカウントへのアクセスを回復できます。

今回実装した方法は一例であり、実際のプロダクション環境では、さらにエラーハンドリングやバリデーションを追加することが望ましいです。また、フロントエンドでパスワードリセットのUIを構築し、ユーザーにより良いエクスペリエンスを提供することも重要です。

最後

いつもお世話になっています。この記事を楽しんで、新しいことを学べたら嬉しいです。😊

今度の記事でお会いしましょう!この記事が気に入ったら、私を応援するために「LIKE」を押して登録してください。ありがとうございました。

Ref

Bình luận

Bài viết tương tự

- vừa được xem lúc

Cách mình "hack" được vào hẹ thống của SMAS để xem điểm.

Cách mà mình "hack" được vào hệ thống của SMAS. Thật ra dùng từ hack cũng không đúng lắm, chỉ là một vài trick để lừa hệ thống mà thôi.

0 0 146

- vừa được xem lúc

[NodeJs] Tạo QR Code trong nodeJs với qrcode

Tạo mã QR Code trong nodejs với qrcode. QR Code là gì. Tạo QR code với qrcode. Cài đặt thư viện qrcode.

0 0 34

- vừa được xem lúc

Áp dụng kiến trúc 3 Layer Architecture vào project NodeJS

The problem encountered. Các framework nodejs phổ biết như Express cho phép chúng ta dễ dàng tạo ra Resful API xử lí các request từ phía client một cách nhanh chóng và linh hoạt.

0 0 80

- vừa được xem lúc

Router, Controller trong Express

Mở đầu. Xin chào các bạn mình đã quay trở lại rồi đây, tiếp tục với series Nodejs cơ bản thì hôm nay mình sẽ giới thiệu đến các bạn Express Router và Controller.

0 0 43

- vừa được xem lúc

Xây dựng CRUD RESTful API sử dụng Node, Express, MongoDB.

Introduction. Trong phạm vi bài viết này chúng ta sẽ cùng tìm hiểu về cách tạo restful api với Node, Express và MongoDB. . Xử lý các hoạt động crud.

0 0 226

- vừa được xem lúc

Rate time limit trong NodeJS

Chào các bạn, lại là mình đây. Hôm nay mình xin giới thiệu tới các bạn một kỹ thuật rất hay ho và hữu ích đó là Rate Limiting. 1. Rate Limiting là gì.

0 0 64